"csv" --- CSV ファイルの読み書き
********************************

**ソースコード:** Lib/csv.py

======================================================================

CSV (Comma Separated Values、カンマ区切り値列) と呼ばれる形式は、 スプ
レッドシートやデータベース間でのデータのインポートやエクスポートにおけ
る最も一般的な形式です。 CSVフォーマットは、 **RFC 4180** によって標準
的な方法でフォーマットを記述する試みが行われる以前から長年使用されまし
た。明確に定義された標準がないということは、異なるアプリケーション に
よって生成されたり取り込まれたりするデータ間では、しばしば微妙な違いが
発生するということを意味します。こうした違いのために、複数のデータ源か
ら得られた CSV ファイルを処理する作業が鬱陶しいものになることがありま
す。とはいえ、デリミタ (delimiter) やクオート文字の 相違はあっても、全
体的な形式は十分似通っているため、こうしたデータを効率的に操作し、デー
タの読み書きにおける細々としたことをプログラマ から隠蔽するような単一
のモジュールを書くことは可能です。

"csv" モジュールでは、CSV 形式で書かれたテーブル状のデータを読み書きす
るためのクラスを実装しています。このモジュールを使うことで、プログラマ
は Excel で使われている CSV  形式に関して詳しい知識をもっていなくても
、 "このデータを Excel で推奨されている形式で書いてください" とか、 "
データを Excel で作成されたこのファイルから読み出してください" と言う
ことができます。プログラマはまた、他のアプリケーションが解釈できる CSV
形式を記述したり、独自の特殊な目的をもった CSV 形式を定義することがで
きます。

"csv" モジュールの "reader" および "writer" オブジェクトはシーケンス型
を読み書きします。プログラマは "DictReader" や "DictWriter" クラスを使
うことで、データを辞書形式で読み書きすることもできます。

参考:

  **PEP 305** - CSV File API
     Python へのこのモジュールの追加を提案している Python 改良案 (PEP:
     Python Enhancement Proposal)。


モジュールコンテンツ
====================

"csv" モジュールでは以下の関数を定義しています:

csv.reader(csvfile, dialect='excel', **fmtparams)

   Return a reader object that will process lines from the given
   *csvfile*.  A csvfile must be an iterable of strings, each in the
   reader's defined csv format. A csvfile is most commonly a file-like
   object or list. If *csvfile* is a file object, it should be opened
   with "newline=''". [1]  An optional *dialect* parameter can be
   given which is used to define a set of parameters specific to a
   particular CSV dialect.  It may be an instance of a subclass of the
   "Dialect" class or one of the strings returned by the
   "list_dialects()" function.  The other optional *fmtparams* keyword
   arguments can be given to override individual formatting parameters
   in the current dialect.  For full details about the dialect and
   formatting parameters, see section Dialect クラスと書式化パラメータ
   .

   csv ファイルから読み込まれた各行は、文字列のリストとして返されます
   。"QUOTE_NONNUMERIC" フォーマットオプションが指定された場合を除き、
   データ型の変換が自動的に行われることはありません (このオプションが
   指定された場合、クォートされていないフィールドは浮動小数点数に変換
   されます)。

   短い利用例:

      >>> import csv
      >>> with open('eggs.csv', newline='') as csvfile:
      ...     spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
      ...     for row in spamreader:
      ...         print(', '.join(row))
      Spam, Spam, Spam, Spam, Spam, Baked Beans
      Spam, Lovely Spam, Wonderful Spam

csv.writer(csvfile, dialect='excel', **fmtparams)

   ユーザが与えたデータをデリミタで区切られた文字列に変換し、与えられ
   たファイルオブジェクトに書き込むための writer オブジェクトを返しま
   す。 *csvfile* は "write()" メソッドを持つ任意のオブジェクトです。
   *csvfile* がファイルオブジェクトの場合、 "newline=''" として開くべ
   きです [1] 。オプションとして *dialect* 引数を与えることができ、利
   用するCSV表現形式(dialect)を指定することができます。 *dialect* パラ
   メータは "Dialect" クラスのサブクラスのインスタンスか、
   "list_dialects()" 関数が返す文字列の1つにすることができます。別のオ
   プション引数である *fmtparams* キーワード引数は、現在の表現形式にお
   ける個々の書式パラメータを上書きするために与えることができます。
   dialect と書式パラメータについての詳細は、 Dialect クラスと書式化パ
   ラメータ 節を参照してください。 DB API を実装するモジュールとのイン
   ターフェースを可能な限り容易にするために、 "None" は空文字列として
   書き込まれます。この処理は可逆な変換ではありませんが、SQL で NULL
   データ値を CSV にダンプする処理を、 "cursor.fetch*" 呼び出しによっ
   て返されたデータを前処理することなく簡単に行うことができます。他の
   非文字列データは、書き出される前に "str()" を使って文字列に変換され
   ます。

   短い利用例:

      import csv
      with open('eggs.csv', 'w', newline='') as csvfile:
          spamwriter = csv.writer(csvfile, delimiter=' ',
                                  quotechar='|', quoting=csv.QUOTE_MINIMAL)
          spamwriter.writerow(['Spam'] * 5 + ['Baked Beans'])
          spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])

csv.register_dialect(name[, dialect[, **fmtparams]])

   *dialect* を *name* と関連付けます。 *name* は文字列でなければなり
   ません。表現形式(dialect)は "Dialect" のサブクラスを渡すか、または
   キーワード引数 *fmtparams* 、もしくは両方で指定できますが、キーワー
   ド引数の方が優先されます。表現形式と書式化パラメータについての詳細
   は、 Dialect クラスと書式化パラメータ 節を参照してください。

csv.unregister_dialect(name)

   *name* に関連づけられた表現形式を表現形式レジストリから削除します。
   *name* が表現形式名でない場合には "Error" を送出します。

csv.get_dialect(name)

   *name* に関連づけられた表現形式を返します。 *name* が表現形式名でな
   い場合には "Error" を送出します。この関数は不変の "Dialect" を返し
   ます。

csv.list_dialects()

   登録されている全ての表現形式を返します。

csv.field_size_limit([new_limit])

   パーサが許容する現在の最大フィールドサイズを返します。 *new_limit*
   が渡されたときは、その値が新しい上限になります。

"csv" モジュールでは以下のクラスを定義しています:

class csv.DictReader(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)

   通常の reader のように動作しますが、個々の行の情報を "dict" にマッ
   プするオブジェクトを生成します。マップのキーは省略可能な
   *fieldnames* パラメータで与えられます。

   The *fieldnames* parameter is a *sequence*.  If *fieldnames* is
   omitted, the values in the first row of file *f* will be used as
   the fieldnames and will be omitted from the results. If
   *fieldnames* is provided, they will be used and the first row will
   be included in the results.  Regardless of how the fieldnames are
   determined, the dictionary preserves their original ordering.

   行がフィールド名より多くのフィールドを持っていた場合、残りのデータ
   はリストに入れられて、 *restkey* により指定されたフィールド名 (デフ
   ォルトでは "None") で保存されます。空白でない行がフィールド名よりも
   少ないフィールドしか持たない場合、足りない値は *restval* の値 (デフ
   ォルトは "None" ) によって埋められます。

   その他の省略可能またはキーワード形式のパラメータは、ベースになって
   いる "reader" インスタンスに渡されます。

   *fieldnames* に渡された引数がイテレータの場合、 "list" に変換されま
   す。

   バージョン 3.6 で変更: 返される行の型は "OrderedDict" になりました
   。

   バージョン 3.8 で変更: 返される行の型は "dict" になりました。

   短い利用例:

      >>> import csv
      >>> with open('names.csv', newline='') as csvfile:
      ...     reader = csv.DictReader(csvfile)
      ...     for row in reader:
      ...         print(row['first_name'], row['last_name'])
      ...
      Eric Idle
      John Cleese

      >>> print(row)
      {'first_name': 'John', 'last_name': 'Cleese'}

class csv.DictWriter(f, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds)

   通常の writer のように動作しますが、辞書を出力行にマップするオブジ
   ェクトを生成します。 *fieldnames* パラメータは、"writerow()" メソッ
   ドに渡された辞書の値がどのような順番でファイル *f* に書かれるかを指
   定するキーの "sequence" です。 "writerow()" メソッドに渡された辞書
   に *fieldnames* には存在しないキーが含まれている場合、オプションの
   *extrasaction* パラメータによってどんな動作を行うかが指定されます。
   この値がデフォルト値である "'raise'" に設定されている場合、
   "ValueError" が送出されます。 "'ignore'" に設定されている場合、辞書
   の余分な値は無視されます。その他のパラメータはベースになっている
   "writer" インスタンスに渡されます。

   "DictReader" クラスとは異なり、 "DictWriter" の *fieldnames* パラメ
   ータは省略可能ではありません。

   *fieldnames* に渡された引数がイテレータの場合、 "list" に変換されま
   す。

   短い利用例:

      import csv

      with open('names.csv', 'w', newline='') as csvfile:
          fieldnames = ['first_name', 'last_name']
          writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

          writer.writeheader()
          writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'})
          writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'})
          writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})

class csv.Dialect

   "Dialect" クラスはコンテナクラスです。その属性に、ダブルクォート、
   空白文字、デリミタなどの扱い方に関する情報を含みます。CSV には厳密
   な規格がないため、アプリケーションによって生成される CSV データはそ
   れぞれ僅かに異なります。 "Dialect" クラスのインスタンスは "reader"
   と "writer" のインスタンスの挙動を定義します。

   All available "Dialect" names are returned by "list_dialects()",
   and they can be registered with specific "reader" and "writer"
   classes through their initializer ("__init__") functions like this:

      import csv

      with open('students.csv', 'w', newline='') as csvfile:
          writer = csv.writer(csvfile, dialect='unix')

class csv.excel

   "excel" クラスは Excel で生成される CSV ファイルの通常のプロパティ
   を定義します。これは "'excel'" という名前の dialect として登録され
   ています。

class csv.excel_tab

   "excel_tab" クラスは Excel で生成されるタブ分割ファイルの通常のプロ
   パティを定義します。これは "'excel-tab'" という名前の dialect とし
   て登録されています。

class csv.unix_dialect

   "unix_dialect" クラスは UNIX システムで生成される CSV ファイルの通
   常のプロパティ (行終端記号として "'\n'" を用い全てのフィールドをク
   ォートするもの) を定義します。これは "'unix'" という名前の dialect
   として登録されています。

   Added in version 3.2.

class csv.Sniffer

   "Sniffer" クラスは CSV ファイルの書式を推理するために用いられるクラ
   スです。

   "Sniffer" クラスではメソッドを二つ提供しています:

   sniff(sample, delimiters=None)

      与えられた *sample* を解析し、発見されたパラメータを反映した
      "Dialect" サブクラスを返します。オプションの *delimiters* パラメ
      ータを与えた場合、有効なデリミタ文字を含んでいるはずの文字列とし
      て解釈されます。

   has_header(sample)

      Analyze the sample text (presumed to be in CSV format) and
      return "True" if the first row appears to be a series of column
      headers. Inspecting each column, one of two key criteria will be
      considered to estimate if the sample contains a header:

      * 2番目からn番目の行は数値を含みます。

      * the second through n-th rows contain strings where at least
        one value's length differs from that of the putative header of
        that column.

      1 行目の後の 20 行がサンプリングされます。半分以上の行 + 列が条
      件を満たす場合、 "True" が返されます。

   注釈:

     このメソッドは大雑把なヒューリスティックであり、結果が偽陽性や偽
     陰性である可能性があります。

"Sniffer" の利用例:

   with open('example.csv', newline='') as csvfile:
       dialect = csv.Sniffer().sniff(csvfile.read(1024))
       csvfile.seek(0)
       reader = csv.reader(csvfile, dialect)
       # ... process CSV file contents here ...

"csv" モジュールでは以下の定数を定義しています:

csv.QUOTE_ALL

   "writer" オブジェクトに対し、全てのフィールドをクオートするように指
   示します。

csv.QUOTE_MINIMAL

   "writer" オブジェクトに対し、 *delimiter* 、 *quotechar* または
   *lineterminator* に含まれる任意の文字のような特別な文字を含むフィー
   ルドだけをクオートするように指示します。

csv.QUOTE_NONNUMERIC

   "writer" オブジェクトに対し、全ての非数値フィールドをクオートするよ
   うに指示します。

   "reader" オブジェクトに、クォーテーションで囲まれていないすべてのフ
   ィールドを *float* 型に変換するよう指示します。

csv.QUOTE_NONE

   "writer" オブジェクトに対し、フィールドを決してクオートしないように
   指示します。現在の *delimiter* が出力データ中に現れた場合、現在設定
   されている *escapechar* 文字が前に付けられます。 *escapechar* がセ
   ットされていない場合、エスケープが必要な文字に遭遇した writer は
   "Error" を送出します。

   "reader" オブジェクトに、クオート文字に対する特殊処理を行わないよう
   指示します。

csv.QUOTE_NOTNULL

   Instructs "writer" objects to quote all fields which are not
   "None".  This is similar to "QUOTE_ALL", except that if a field
   value is "None" an empty (unquoted) string is written.

   Instructs "reader" objects to interpret an empty (unquoted) field
   as "None" and to otherwise behave as "QUOTE_ALL".

   Added in version 3.12.

csv.QUOTE_STRINGS

   Instructs "writer" objects to always place quotes around fields
   which are strings.  This is similar to "QUOTE_NONNUMERIC", except
   that if a field value is "None" an empty (unquoted) string is
   written.

   Instructs "reader" objects to interpret an empty (unquoted) string
   as "None" and to otherwise behave as "QUOTE_NONNUMERIC".

   Added in version 3.12.

注釈:

  Due to a bug, constants "QUOTE_NOTNULL" and "QUOTE_STRINGS" do not
  affect behaviour of "reader" objects. This bug is fixed in Python
  3.13.

"csv" モジュールでは以下の例外を定義しています:

exception csv.Error

   全ての関数において、エラーが検出された際に送出される例外です。


Dialect クラスと書式化パラメータ
================================

To make it easier to specify the format of input and output records,
specific formatting parameters are grouped together into dialects.  A
dialect is a subclass of the "Dialect" class containing various
attributes describing the format of the CSV file.  When creating
"reader" or "writer" objects, the programmer can specify a string or a
subclass of the "Dialect" class as the dialect parameter.  In addition
to, or instead of, the *dialect* parameter, the programmer can also
specify individual formatting parameters, which have the same names as
the attributes defined below for the "Dialect" class.

Dialect は以下の属性をサポートしています:

Dialect.delimiter

   フィールド間を分割するのに用いられる 1 文字からなる文字列です。デフ
   ォルトでは "','" です。

Dialect.doublequote

   フィールド内に現れた *quotechar* のインスタンスで、クオートではない
   その文字自身でなければならない文字をどのようにクオートするかを制御
   します。 "True" の場合、この文字は二重化されます。 "False" の場合、
   *escapechar* は *quotechar* の前に置かれます。デフォルトでは "True"
   です。

   出力においては、 *doublequote* が "False" で *escapechar* がセット
   されていない場合、フィールド内に *quotechar* が現れると "Error" が
   送出されます。

Dialect.escapechar

   writer が、 *quoting* が "QUOTE_NONE" に設定されている場合に
   *delimiter* をエスケープするため、および、 *doublequote* が "False"
   の場合に *quotechar* をエスケープするために用いられる、 1 文字から
   なる文字列です。読み込み時には *escapechar* はそれに引き続く文字の
   特別な意味を取り除きます。デフォルトでは "None" で、エスケープを行
   ないません。

   バージョン 3.11 で変更: 空の *escapechar* は許可されていません。

Dialect.lineterminator

   "writer" が作り出す各行を終端する際に用いられる文字列です。デフォル
   トでは "'\r\n'" です。

   注釈:

     "reader" は "'\r'" または "'\n'" のどちらかを行末と認識するように
     ハードコードされており、 *lineterminator* を無視します。この振る
     舞いは将来変更されるかもしれません。

Dialect.quotechar

   *delimiter* や *quotechar* といった特殊文字を含むか、改行文字を含む
   フィールドをクオートする際に用いられる 1 文字からなる文字列です。デ
   フォルトでは "'"'" です。

   バージョン 3.11 で変更: 空の *quotechar* は許可されていません。

Dialect.quoting

   クオートがいつ writer によって生成されるか、また reader によって認
   識されるかを制御します。QUOTE_* constants  のいずれかをとることがで
   き、デフォルトでは "QUOTE_MINIMAL" です。

Dialect.skipinitialspace

   "True" の場合、 *delimiter* の直後に続く空白は無視されます。デフォ
   ルトでは "False" です。

Dialect.strict

   "True" の場合、 不正な CSV 入力に対して "Error" を送出します。デフ
   ォルトでは "False" です。


reader オブジェクト
===================

reader オブジェクト("DictReader" インスタンス、および "reader()" 関数
によって返されたオブジェクト) は、以下の public なメソッドを持っていま
す:

csvreader.__next__()

   reader の反復可能なオブジェクトから、現在の表現形式 ("Dialect") に
   基づいて次の行を解析してリスト（オブジェクトが "reader()" から返さ
   れた場合）または辞書 （ "DictReader" のインスタンスの場合）として返
   します。通常は "next(reader)" のようにして呼び出すことになります。

reader オブジェクトには以下の公開属性があります:

csvreader.dialect

   パーサで使われる表現形式の読み出し専用の記述です。

csvreader.line_num

   ソースイテレータから読んだ行数です。この数は返されるレコードの数と
   は、レコードが複数行に亘ることがあるので、一致しません。

DictReader オブジェクトは、以下の public な属性を持っています:

DictReader.fieldnames

   オブジェクトを生成するときに渡されなかった場合、この属性は最初のア
   クセス時か、ファイルから最初のレコードを読み出したときに初期化され
   ます。


writer オブジェクト
===================

"writer" オブジェクト("DictWriter" インスタンス、および  "writer()" 関
数によって返されたオブジェクト) は、以下の public なメソッドを持ってい
ます: *row* には、 "writer" オブジェクトの場合には文字列か数値のイテラ
ブルを指定し、 "DictWriter" オブジェクトの場合はフィールド名をキーとし
て対応する文字列か数値を格納した辞書オブジェクトを指定します(数値は
"str()" で変換されます)。複素数を出力する場合、値をかっこで囲んで出力
します。このため、CSV ファイルを読み込むアプリケーションで（そのアプリ
ケーションが複素数をサポートしていたとしても）問題が発生する場合があり
ます。

csvwriter.writerow(row)

   現在の表現形式 ("Dialect".)に沿ってフォーマットされた *row* パラメ
   ータを writer のファイルオブジェクトに書き込みます。ファイルオブジ
   ェクトの *write* メソッドを呼び出した際の戻り値を返します。

   バージョン 3.5 で変更: 任意のイテラブルのサポートの追加。

csvwriter.writerows(rows)

   *rows* 引数 (上で解説した *row* オブジェクトのイテラブル) の全ての
   要素を現在の表現形式に基づいて書式化し、writer のファイルオブジェク
   トに書き込みます。

writer オブジェクトには以下の公開属性があります:

csvwriter.dialect

   writer で使われる表現形式の読み出し専用の記述です。

DictWriter のオブジェクトは以下の public メソッドを持っています:

DictWriter.writeheader()

   Write a row with the field names (as specified in the constructor)
   to the writer's file object, formatted according to the current
   dialect. Return the return value of the "csvwriter.writerow()" call
   used internally.

   Added in version 3.2.

   バージョン 3.8 で変更: "writeheader()" は内部的に利用している
   "csvwriter.writerow()" メソッドの返り値を返すようになりました。


使用例
======

最も簡単な CSV ファイル読み込みの例です:

   import csv
   with open('some.csv', newline='') as f:
       reader = csv.reader(f)
       for row in reader:
           print(row)

別の書式での読み込み:

   import csv
   with open('passwd', newline='') as f:
       reader = csv.reader(f, delimiter=':', quoting=csv.QUOTE_NONE)
       for row in reader:
           print(row)

上に対して、単純な書き込みのプログラム例は以下のようになります。

   import csv
   with open('some.csv', 'w', newline='') as f:
       writer = csv.writer(f)
       writer.writerows(someiterable)

"open()" が CSV ファイルの読み込みに使われるため、ファイルはデフォルト
ではシステムのデフォルトエンコーディングでユニコード文字列にデコードさ
れます ("locale.getencoding()" を参照)。他のエンコーディングを用いてデ
コードするには、open の引数 "encoding" を設定して、以下のようにします:

   import csv
   with open('some.csv', newline='', encoding='utf-8') as f:
       reader = csv.reader(f)
       for row in reader:
           print(row)

システムのデフォルトエンコーディング以外で書き込む場合も同様です。出力
ファイルを開く際に引数 "encoding" を明示してください。

新しい表現形式の登録:

   import csv
   csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
   with open('passwd', newline='') as f:
       reader = csv.reader(f, 'unixpwd')

もう少し手の込んだ reader の使い方 --- エラーを捉えてレポートします。

   import csv, sys
   filename = 'some.csv'
   with open(filename, newline='') as f:
       reader = csv.reader(f)
       try:
           for row in reader:
               print(row)
       except csv.Error as e:
           sys.exit('file {}, line {}: {}'.format(filename, reader.line_num, e))

このモジュールは文字列の解析は直接サポートしませんが、簡単にできます。

   import csv
   for row in csv.reader(['one,two,three']):
       print(row)

-[ 脚注 ]-

[1] "newline=''" が指定されない場合、クォートされたフィールド内の改行
    は適切に解釈されず、書き込み時に "\r\n" を行末に用いる処理系では余
    分な "\r" が追加されてしまいます。csv モジュールは独自
    (*universal*) の改行処理を行うため、"newline=''" を指定することは
    常に安全です。
