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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(use text.csv)
(use srfi-42)
(define (parse-csv line)
  (call-with-input-string line
    (lambda (port) ((make-csv-reader #\,) port))))
(define (splitCSV line)
  (do-ec (: elt (parse-csv line))
         (: i 1)
         (format #t "~a => ~a~%" i elt)))

(splitCSV "\"aaa\",\"b
bb\",\"ccc\",zzz,\"y\"\"Y\"\"y\",xxx
")

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(use text.csv)

(define (splitCSV str)
  (define (numberling l)
    (let loop ((l l) (n 1))
      (unless (null? l)
              (format #t "~d => ~a~%" n (car l))
              (loop (cdr l) (+ n 1)))))
  (call-with-input-string str
    (lambda (in)
      (port-for-each
       (pa$ numberling)
       (pa$ (make-csv-reader #\,) in)))))

call-with-input-stringには「portを引数に取る手続き」であれば何でも渡せるので、
(make-csv-reader #\,) の結果をそのまま渡すことができます。
lambdaにくるむ必要はありません。

それから、単純なインデックスつきループであれば
for-each-with-indexというのがあります。

なので、こんなふうに書けます:
1
2
3
4
5
6
(use text.csv)
(use gauche.sequence)

(define (splitCSV line)
  (for-each-with-index (cut print <>" => "<>)
      (call-with-input-string line (make-csv-reader #\,))))

おっと、カラムの表示は1からスタートでしたか。そしたらcutは使えないですね。
1
2
3
4
5
6
7
(use text.csv)
(use gauche.sequence)

(define (splitCSV line)
  (for-each-with-index
   (lambda (i e) (print (+ i 1)" => "e))
   (call-with-input-string line (make-csv-reader #\,))))

Index

Feed

Other

Link

Pathtraq

loading...