Examples/CSVファイルを読み込む

Last-modified: 2021-09-21 (火) 00:03:19

概要

  • 指定した入力ポートからデータを読み込んで、SKILL で処理しやすい形式のデータを返す。
  • ダブルクオートの処理や空白文字の処理は Microsoft Excel の処理を基準にする。
  • CR、LF、CR-LF のどの改行方式でも対応する。
  • 効率優先の実装。
  • 関数としては SKILL 組み込みの以外のものは使わない。

jp_wikiwiki_aiou_Csv_toRecordList

  • 出力結果は〈〈値のリスト〉のリスト〉とする。

jp_wikiwiki_aiou_Csv_toMapList

  • 出力結果は〈〈〈キーと値のタプル〉のリスト〉のリスト〉とする。
  • ヘッダ行のフィールド数と本体のフィールド数が違う場合の処理は Windows PowerShell の Import-Csv コマンドを基準にする。

コード

(inScheme
  (define (jp_wikiwiki_aiou_Csv_toRecordList inputPort)
    (letseq
      (
      (inputPort__isEOF         nil) ; boolean
      (inputPort__bufferIsReady nil) ; boolean
      (inputPort__buffer        nil) ; char
      (inputPort_readChar (lambda ()
        (cond
          (inputPort__isEOF nil) ; nil as eof-object
          (inputPort__bufferIsReady
            (setq inputPort__bufferIsReady nil)
            inputPort__buffer
          )
          (else
            (setq inputPort__buffer (getc inputPort))
            (setq inputPort__isEOF (null inputPort__buffer))
            inputPort__buffer
          )
        )
      ))
      (inputPort_peekChar (lambda ()
        (cond
          (inputPort__isEOF nil) ; nil as eof-object
          (inputPort__bufferIsReady inputPort__buffer)
          (else
            (setq inputPort__buffer (getc inputPort))
            (setq inputPort__bufferIsReady t)
            (setq inputPort__isEOF (null inputPort__buffer))
            inputPort__buffer
          )
        )
      ))
      (CharList_toString (lambda (this)
        (if this (apply strcat this) "")
      ))
      )
      (if (null (inputPort_peekChar)) nil ; null as eof-object?
        (letseq
          (
          (chars   (list nil)) (chars_last   chars  )
          (fields  (list nil)) (fields_last  fields )
          (records (list nil)) (records_last records)
          )
          (let parseLine ((c (inputPort_readChar)))
            (cond
              ((null c) ; null as eof-object?
                (when (or (pairp (cdr chars)) (pairp (cdr fields)))
                  (setcdr fields_last (list (CharList_toString (cdr chars))))
                  (setcdr records_last (list (cdr fields)))
                )
                (cdr records)
              ) ; null
              ((eq c '\r)
                (let ((nextChar (inputPort_peekChar)))
                  (cond
                    ((null   nextChar) nil)
                    ((eq '\n nextChar) (inputPort_readChar))
                  )
                  (if (or (pairp (cdr chars)) (pairp (cdr fields)))
                    (begin
                      (setcdr fields_last (list (CharList_toString (cdr chars))))
                      (setcdr records_last (list (cdr fields)))
                      (setq   records_last (cdr records_last))
                    )
                  )
                  (setcdr fields nil) (setq fields_last fields)
                  (setcdr chars  nil) (setq chars_last  chars )
                  (parseLine (inputPort_readChar))
                )
              ) ; '\r
              ((eq c '\n)
                (when (or (pairp (cdr chars)) (pairp (cdr fields)))
                  (setcdr fields_last  (list (CharList_toString (cdr chars))))
                  (setcdr records_last (list (cdr fields)))
                  (setq   records_last (cdr records_last))
                )
                (setcdr fields nil) (setq fields_last fields)
                (setcdr chars  nil) (setq chars_last  chars )
                (parseLine (inputPort_readChar))
              ) ; '\n
              ((eq c '\")
                (if (null (cdr chars))
                  (let parseQuoted ((c (inputPort_readChar)))
                    (cond
                      ((null c) ; null as eof-object?
                        (when (or (pairp (cdr chars)) (pairp (cdr fields)))
                          (setcdr fields_last  (list (CharList_toString (cdr chars))))
                          (setcdr records_last (list (cdr fields)))
                        )
                        (cdr records)
                      )
                      ((eq c '\")
                        (case (inputPort_peekChar)
                          ((\")
                            (inputPort_readChar)
                            (setcdr chars_last (list '\"))
                            (setq   chars_last (cdr chars_last))
                            (parseQuoted (inputPort_readChar))
                          )
                          ((\,) (parseLine (inputPort_readChar)))
                          (else (parseQuoted (inputPort_readChar)))
                        )
                      )
                      (else
                        (setcdr chars_last (list c))
                        (setq   chars_last (cdr chars_last))
                        (parseQuoted (inputPort_readChar))
                      )
                    )
                  ) ; let parseQuoted
                ; else
                  (begin
                    (setcdr chars_last (list c))
                    (setq   chars_last (cdr chars_last))
                    (parseLine (inputPort_readChar))
                  )
                )
              ) ; '\"
              ((eq c '\,)
                (setcdr fields_last (list (CharList_toString (cdr chars))))
                (setq   fields_last (cdr fields_last))
                (setcdr chars nil) (setq chars_last chars)
                (parseLine (inputPort_readChar))
              ) ; '\,
              (t
                (setcdr chars_last (list c))
                (setq   chars_last (cdr chars_last))
                (parseLine (inputPort_readChar))
              )
            ) ; cond
          ) ; let parseLine
        ) ; letseq
      ) ; if null
    ) ; letseq
  ) ; define jp_wikiwiki_aiou_Csv_toRecordList
  (define (jp_wikiwiki_aiou_Csv_toMapList inputPort)
    (let ((rl (jp_wikiwiki_aiou_Csv_toRecordList inputPort)))
      (and rl
        (let ((head (car rl)) (body (cdr rl)))
          (mapcar
            (lambda (values)
              (letseq ((buffer (list nil)) (buffer_last buffer))
                (let keyValue ((ks head) (vs values))
                  (cond
                    ((null ks) (cdr buffer))
                    ((null vs)
                      (setcdr buffer_last (list (list (car ks) "")))
                      (setq   buffer_last (cdr buffer_last))
                      (keyValue (cdr ks) nil)
                    )
                    (t
                      (setcdr buffer_last (list (list (car ks) (car vs))))
                      (setq   buffer_last (cdr buffer_last))
                      (keyValue (cdr ks) (cdr vs))
                    )
                  ) ; cond
                ) ; let keyValue
              ) ; letseq
            ) ; lambda
            body
          ) ; mapcar body
        ) ; let head, body
      ) ; and rl
    ) ; let rl
  ) ; define jp_wikiwiki_aiou_Csv_toMapList
) ; inScheme

使用例

ファイル「Presidents.csv」の中身は以下のとおり。

$ cat Presidents.csv
name,company,address,city
"LINCOLN, Abraham","Benton, John B Jr",6649 N Blue Gum St,New Orleans
"CARTER, Jimmy","Chanay, Jeffrey A Esq",4 B Blue Ridge Blvd,Brighton
"ROOSEVELT, Franklin","Chemel, James L Cpa",8 W Cerritos Ave #54,Bridgeport
"BUSH, George",Feltz Printing Service,639 Main St,Anchorage
"CLINTON, Bill",Printing Dimensions,34 Center St,Hamilton
"OBARAM, Barack","Chapman, Ross E Esq",3 Mcauley Dr,Ashland
$

jp_wikiwiki_aiou_Csv_toRecordList

(letseq
  (
  (inputPort (infile "Presidents.csv"))
  (recordList (jp_wikiwiki_aiou_Csv_toRecordList inputPort))
  )
  (close inputPort)
  recordList
)
→ (
   ("name" "company" "address" "city")
   ("LINCOLN, Abraham" "Benton, John B Jr" "6649 N Blue Gum St" "New Orleans")
   ("CARTER, Jimmy" "Chanay, Jeffrey A Esq" "4 B Blue Ridge Blvd" "Brighton")
   ("ROOSEVELT, Franklin" "Chemel, James L Cpa" "8 W Cerritos Ave #54" "Bridgeport")
   ("BUSH, George" "Feltz Printing Service" "639 Main St" "Anchorage")
   ("CLINTON, Bill" "Printing Dimensions" "34 Center St" "Hamilton")
   ("OBARAM, Barack" "Chapman, Ross E Esq" "3 Mcauley Dr" "Ashland")
   )

jp_wikiwiki_aiou_Csv_toMapList

(letseq
  (
  (inputPort (infile "Presidents.csv"))
  (mapList (jp_wikiwiki_aiou_Csv_toMapList inputPort))
  )
  (close inputPort)
  mapList
)
→ (
   (("name" "LINCOLN, Abraham") ("company" "Benton, John B Jr") ("address" "6649 N Blue Gum St") ("city" "New Orleans"))
   (("name" "CARTER, Jimmy") ("company" "Chanay, Jeffrey A Esq") ("address" "4 B Blue Ridge Blvd") ("city" "Brighton"))
   (("name" "ROOSEVELT, Franklin") ("company" "Chemel, James L Cpa") ("address" "8 W Cerritos Ave #54") ("city" "Bridgeport"))
   (("name" "BUSH, George") ("company" "Feltz Printing Service") ("address" "639 Main St") ("city" "Anchorage"))
   (("name" "CLINTON, Bill") ("company" "Printing Dimensions") ("address" "34 Center St") ("city" "Hamilton"))
   (("name" "OBARAM, Barack") ("company" "Chapman, Ross E Esq") ("address" "3 Mcauley Dr") ("city" "Ashland"))
   )