แทนที่ ช่องว่างหลายๆตัวด้วย ช่องว่างตัวเดียว

โจทย์ข้อนี้นำมาจากหนังสือ The C Programming Language ของ BRIAN W. KERNIGHAN, DENNIS M.RITCHIE บทแรกนะครับ ซึ่งก็ไม่ใช่โจทย์ยากอะไรมากมาย แต่ผมอยากลองดูว่าในหลายๆภาษาแต่ละคนที่ทำออกมายังไง โจทย์มีอยู่ว่า

Exercise 1-9. Write a program to copy its input to its output, replacing each string of one or more blanks by a single blank.

เช่น ใส่ input เป็น

abc defg hijk

จะได้ output เป็น abc defg hijk

คือแปลงจากช่องว่างหลายๆช่องให้เหลือแค่ช่องเดียว

นี่คือที่ผมทำ เป็นภาษา c

#include <stdio.h>
#define BLANK ' '
#define NOTBLANK '\0'
int main()
{
        int c, prev_char;
        prev_char = NOTBLANK;
        while ((c = getchar()) != EOF)
                if (prev_char == BLANK && c != BLANK) {
                        putchar(c);
                        prev_char = NOTBLANK;
                } else if (prev_char == NOTBLANK) {
                        if (c == BLANK)
                                prev_char = c;
 
                        putchar(c);
                }
        return 0;
}

และอันนี้ทำด้วย haskell

f::String->String
 
f [] = []
f (x:xs) | x == ' ' = ' ':h xs
         | otherwise = x:f xs
        where
                h [] = []
                h (x:xs) | x == ' ' = h xs
                         | otherwise = x:f xs

Python แบบใช้ RegEx ครับ

import re
print re.sub("[\s]+", " ", raw_input())

ใช้ split ได้ไหม?

 "abc def   ghi".split(" ").join(" ")

(ruby)

sugree's picture

เอ่อ เขียนด้วย python แล้วโคตรน่าเกลียด

s = 'abc def   ghi'
' '.join(filter(lambda x: x != '', s.split(' ')))
sugree's picture

เอ่อ ผมพลาดเอง มีโหมดพิเศษด้วย

' '.join('abc def   ghi'.split())

ดูดีขึ้นมากระทันหัน

น่าสนใจตรงที่ ตัว join มันกลับทิศกับ ruby

sugree's picture

มีการคุยกันยาวเรื่องนี้ join ควรจะอยู่กับ list หรือ string

โดยส่วนตัวผมก็ว่ามันแหม่งๆ

ดูดีขึ้นจริง ๆ ด้วยครับ อย่างที่พี่ป้อกบอกครับ มันกลับทิศกับ Ruby โดยส่วนตัว ผมรู้สึกว่าของ Ruby เข้าใจง่ายกว่าครับ

ใน .NET มันก็กลับทิศ แต่ไม่ค่อยรู้สึกว่ามันแหม่งๆ

string one = "abc def     ghijk";
string two = string.Join(" ", one.Split( new string[] { " "},
                StringSplitOptions.RemoveEmptyEntries));

พออ่าน ruby แล้วมาอ่าน python ก็รู้สึกว่ามันแหม่งๆเหมือนกัน

ดูเหมือนว่าภาษาอื่นจะมองว่า " " เป็นตัวคั่นแล้ว เวลา split แล้วเป็นช่องว่างๆหลายช่องก็จะตัดทิ้งหมด แต่ .NET มันดันเก็บเข้ามาเป็นสตริงว่างๆด้วย พอเอามา join มันก็กลายเป็นช่องว่าง
เลยต้องใส่ว่า StringSplitOptions.RemoveEmptyEntries ด้วย

ruby

"abc   def    ghi".scan(/\w+\s?/).join

ใช้ RegEx ดูบ้าง
 "abc def    ghi".gsub!(/[\s\b\v]+/," ")

ลองใช้ foldl ใน haskell

myscan (x:xs) = reverse $ foldl chkSpace [x] xs
 
chkSpace acc@(x:_) cur 
    | isSpace x && isSpace cur = acc
    | otherwise = cur:acc

$ ที่อยู่ระหว่าง reverse กับ foldl ใช้ทำอะไรเหรอครับ

ไช่ๆ สมัยแรกๆที่ผมเห็น haskell ผมจะสงสัยมากเลยว่า $ นี่มันคืออะไร
พยายาม search ดู คำอธิบาย ก็หาไม่เจอ

ตัว $ มันบอกว่า ทำฝั่งขวาให้เสร็จก่อน
แล้วค่อยเอาผลลัพท์มาให้ฝั่งซ้าย

ตัวข้างบน ถ้าไม่ใช้ $ เขียน, ก็สามารถเขียนแบบนี้แทนได้

reverse (foldl chkSpace [x] xs)

นิยามมันใน Prelude เป็นอย่างนี้ครับ

($)            :: (a -> b) -> a -> b
f $ x           = f x

php

>print ereg_replace('[ +]',' ', 'abc  def    ghi');</blockcode>

haskell แบบใช้ built-in library

unwords $ words "abc  def    ghi"
หรือ
(unwords . words) "abc   def     ghi"

Ruby

"abc  def    ghi".squeeze!(" ")

ย้าย Codenone

ประกาศย้าย Codenone ไปใช้ Forum ของ Blognone แทนครับ ตามไปตั้งกระทู้ต่อได้ที่ Codenone Forum (รายละเอียดอ่านจากกระทู้ ย้าย Codenone ไปรวมกับ Blognone)

กระทู้เก่าๆ จะย้ายตามไปในภายหลัง ตอนนี้ปิดการโพสต์กระทู้ไว้ เหลือไว้เฉพาะอ้างอิงเท่านั้น