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 - awk

% cat test.csv
"aaa","b
bb","ccc",zzz,"y""Y""y",xxx
"aaa","""","ccc",zzz,"y""Y""y",xxx,"u,v"
% awk -f csv.awk test.csv
1 => aaa
2 => b
bb
3 => ccc
4 => zzz
5 => y"Y"y
6 => xxx

1 => aaa
2 => "
3 => ccc
4 => zzz
5 => y"Y"y
6 => xxx
7 => u,v
 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
49
50
51
52
53
BEGIN {
	s = "" # バッファ
	r = 0 # フィールド番号
	t = 2 # バッファのどこから " を探すか(覚えておくため)
}

{
	s = s $0
	while (s !‾ /^$/) {

		if (s ‾ /^"/) {	# "で始まる
			
			if (match(substr(s,t), /"/)) {
				if (substr(s,t+RSTART-1) ‾ /^""/) { # 次が"ならスキップしたい
					t += RSTART + 1 ; continue
				}
				# 閉じる"を検出.
			} else {
				# 閉じる"がなければ1行追加
				getline nextline
				s = s "¥n" nextline
				continue
			}
			
			# "で囲まれた部分 ("" が含まれている場合がある)
			s0 = substr(s,2,t+RSTART-3)
			gsub(/""/,"¥"", s0)
			printf("%d => %s¥n", ++r, s0)
			s = substr(s, t+RSTART)

			t = 2 # 戻しておく

			if (s ‾ /^,/) {
				s = substr(s,2)
			} else if (s ‾ /^$/) {
				printf("¥n")
				r = 0
				s = ""
			}
		} else {
			if (match(s, /,/)) {
				printf("%d => %s¥n", ++r, substr(s,1,RSTART-1))
				s = substr(s,RSTART+1)
			} else {
				printf("%d => %s¥n", ++r, s)
				s = ""
			}
		}
	}

	r = 0
	printf "¥n"
}

Index

Feed

Other

Link

Pathtraq

loading...