challenge RFC 4180対応版 CSVレコードの分解

ある関数(splitCSV)に渡された文字列を配列に分解して列ごとに表示してください。
渡される文字列は、CSVデータの1レコードが設定されているとします。

使用するデータはK3形式が元になっている仕様で
エクセルが出力しているような形式です。

書式には次のような特徴があります。
1. 各レコードは「改行」によって区切られている。
2. 各列は「,」によって区切られている。
3. 列のデータは「"」によって囲んでも良い。
4. 列に「,」「改行」「"」いずれかを含む場合「"」で
   囲わなければならない。
5. 列データに「"」を含める場合「""」とする。

本来、改行コードはCRLFですが今回は特に指定しません。

次の入力があった場合
"aaa","b
bb","ccc",zzz,"y""Y""y",xxx

出力は
1 => aaa
2 => b
bb
3 => ccc
4 => zzz
5 => y"Y"y
6 => xxx

となります。
このお題はraynstardさんの投稿によるものです。ご投稿ありがとうございます。助かります。

Posted feedbacks - Ruby

1
2
3
4
5
6
7
8
require 'csv'
def splitCSV(str)
  CSV::Reader.parse(str) do |x|
    i=0; x.each{|d| puts "#{i.succ} => #{d}" }
  end
end
splitCSV('"aaa","b
bb","ccc",zzz,"y""Y""y",xxx')

あえて自力でやってみました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def parse_csv(d)
	records = []
	columns = []
	buffer = ""
	in_quote = false

	i = 0
	while i < d.size
		if d[i] == ?"
			if d[i+1] != ?"
				in_quote = !in_quote
				i += 1
				next
			else
				i += 1
			end
		end
		
		unless in_quote
			if d[i] == ?, || d[i] == ?\n
				columns << buffer
				buffer = ""

				if d[i] == ?\n
					records << columns
					columns = []
				end
				i += 1
				next
			end
		end

		buffer += d[i].chr
		i += 1
	end

	records
end

data=<<EOT
"aaa","b
bb","ccc",zzz,"y""Y""y",xxx
EOT

records=parse_csv(data)
records.first.each_with_index{ |r,index|
	puts "#{index+1} => #{r}"
}

単にデータを加工して出力しただけです. 題意を満たしているかどうか自信がありませんが.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
STR = <<EOS
"aaa","b
bb","ccc",zzz,"y""Y""y",xxx
EOS
def splitCSV(str)
  str.split(/,/).
    map{|x| x.match(/\A"?([^"](?:.|\s)+[^"])"?\z/)[1].gsub('""', '"')}.
    each_with_index{|x, i| print "#{i+1} => #{x}\n"}
end
splitCSV(STR)
exit

Index

Feed

Other

Link

Pathtraq

loading...