14

改行を含むフィールドを持つ CSV ファイルがあります。

A, B, C, D, E, F
123, 456, tree
, very, bla, indigo

(この場合、2 行目の 3 番目のフィールドは「tree\n」です

私は次のことを試しました:

import csv
catalog = csv.reader(open('test.csv', 'rU'), delimiter=",", dialect=csv.excel_tab)
for row in catalog:
    print "Length: ", len(row), row

私が得た結果はこれでした:

Length:  6 ['A', ' B', ' C', ' D', ' E', ' F']
Length:  3 ['123', ' 456', ' tree']
Length:  4 ['   ', ' very', ' bla', ' indigo']

不要な改行をすばやく削除する方法を知っている人はいますか?

ありがとう!

4

6 に答える 6

17

次の Excel スプレッドシートがあるとします。

Excel ファイルによくある「落とし穴」

ノート:

  1. C2 の複数行セル。
  2. C1 と D3 に埋め込まれたコンマ。
  3. 空白のセル、および D4 にスペースがあるセル。

これを Excel で CSV として保存すると、次の csv ファイルが得られます。

A1,B1,"C1,+comma",D1
,B2,"line 1
line 2",D2
,,C3,"D3,+comma"
,,,D4 space

おそらく、空白のセルがまだ意味を持ち、埋め込まれたコンマが正しく処理された状態で、それを Python に読み込みたいと思うでしょう。

したがって、この:

with open("test.csv", 'rU') as csvIN:
    outCSV=(line for line in csv.reader(csvIN, dialect='excel'))

    for row in outCSV:
        print("Length: ", len(row), row) 

Excel で表されるリスト マトリックスの 4x4 リストを正しく生成します。

Length:  4 ['A1', 'B1', 'C1,+comma', 'D1']
Length:  4 ['', 'B2', 'line 1\nline 2', 'D2']
Length:  4 ['', '', 'C3', 'D3,+comma']
Length:  4 ['', '', '', 'D4 space']

投稿した CSV ファイルの例では、フィールドの周りに引用符がなく、「余分な改行」があり、その改行の意味があいまいになっています。新しい行ですか、それとも複数行のフィールドですか?

そのため、次の csv ファイルのみを解釈できます。

A, B, C, D, E, F
123, 456, tree
, very, bla, indigo

次のような一次元リストとして:

with open("test.csv", 'rU') as csvIN:
   outCSV=[field.strip() for row in csv.reader(csvIN, delimiter=',') 
              for field in row if field]

この一次元リストを生成するもの:

['A', 'B', 'C', 'D', 'E', 'F', '123', '456', 'tree', 'very', 'bla', 'indigo']

これは、必要に応じて解釈し、任意のサブ グループに再グループ化できます。

Python の慣用的な再グループ化方法では、次のようにzipを使用します。

>>> zip(*[iter(outCSV)]*6)
[('A', 'B', 'C', 'D', 'E', 'F'), ('123', '456', 'tree', 'very', 'bla', 'indigo')]

または、リストのリストが必要な場合は、これも慣用的です。

>>> [outCSV[i:i+6] for i in range(0, len(outCSV),6)]
[['A', 'B', 'C', 'D', 'E', 'F'], ['123', '456', 'tree', 'very', 'bla', 'indigo']]

CSV ファイルの作成方法を変更できれば、解釈があいまいになりにくくなります。

于 2012-06-22T02:18:31.977 に答える
6

これは、空白でないセルがある場合に機能します

data = [['A', ' B', ' C', ' D', ' E', ' F'],
['123', ' 456', ' tree'],
['   ', ' very', ' bla', ' indigo']]

flat_list = chain.from_iterable(data)
flat_list = [cell for cell in flat_list if cell.strip() != ''] # remove blank cells

rows = [flat_list[i:i+6] for i in range(0, len(flat_list), 6)] # chunk into groups of 6 
print rows 

出力:

[['A', ' B', ' C', ' D', ' E', ' F'], ['123', ' 456', ' tree', ' very', ' bla', ' indigo']]

入力に空白のセルがある場合、これはほとんどの場合機能します。

data = [['A', ' B', ' C', ' D', ' E', ' F'],
['123', ' 456', ' tree'],
['   ', ' very', ' bla', ' indigo']]

clean_rows = []
saved_row = []

for row in data:
    if len(saved_row):
        row_tail = saved_row.pop()
        row[0] = row_tail + row[0]  # reconstitute field broken by newline
        row = saved_row + row       # and reassemble the row (possibly only partially)
    if len(row) >= 6:
        clean_rows.append(row)
        saved_row = []
    else:
        saved_row = row


print clean_rows 

出力:

[['A', ' B', ' C', ' D', ' E', ' F'], ['123', ' 456', ' tree   ', ' very', ' bla', ' indigo']]

ただし、2番目のソリューションでさえ、次のような入力では失敗します

A,B,C,D,E,F\nG
1,2,3,4,5,6

この場合、入力はあいまいであり、次のことを意図しているかどうかを推測できるアルゴリズムはありません。

A,B,C,D,E,F
G\n1,2,3,4,5,6 

(または上記の入力)

これが当てはまる場合は、データを保存している人に戻って、よりきれいな形式で保存する必要があります(CSVファイルの改行は、Excelよりもはるかに優れています)。

于 2012-06-21T21:09:37.093 に答える
1

各行のフィールド数が同じで、フィールドを空にできない場合:

from itertools import izip_longest

nfields = 6
with open(filename) as f:
     fields = (field.strip() for line in f for field in line.split(',') if field)
     for row in izip_longest(*[iter(fields)]*nfields): # grouper recipe*
         print(row)

*ハタのレシピ

出力

('A', 'B', 'C', 'D', 'E', 'F')
('123', '456', 'tree', 'very', 'bla', 'indigo')
于 2012-06-21T21:45:58.650 に答える
1

これはうまくいくはずです。(警告: 脳がコンパイルしたコード)

with open('test.csv', 'rU') as infile:
   data = []
   for line in infile:
       temp_data = line.split(',')
       try:
           while len(temp_data) < 6: #column length
               temp_data.extend(infile.next())
       except StopIteration: pass
       data.append(temp_data)
于 2012-06-21T21:18:13.833 に答える
1

これは CSV モジュールで機能し、空白のフィールドと行を消去します。

import csv
import StringIO

data="""A, B, C, D, E, F
123, 456, tree

,,
, very, bla, indigo"""

f=StringIO.StringIO(data)   #used just to simulate a file. Use your file here...
reader = csv.reader(f)
out=[]
for line in reader:
    line=[x.strip() for x in line if x]   # remove 'if x' if you want blank fields
    if len(line):
        out.append(line)

print out        

版画:

[['A', ' B', ' C', ' D', ' E', ' F'], 
 ['123', '456', 'tree'], 
 ['very', 'bla', 'indigo']]

6列のチャンクでそれが必要な場合:

cols=6        
out=[i for sl in out for i in sl]                      # flatten out
out=[out[i:i+cols] for i in range(0, len(out), cols)]  # rechunk into 'cols' 

版画:

[['A', 'B', 'C', 'D', 'E', 'F'],
 ['123', '456', 'tree', 'very', 'bla', 'indigo']]
于 2012-06-21T21:27:08.543 に答える
0

列数がわかっている場合は、行末を無視してから分割するのが最善の方法です。

このようなもの

with open(filename, 'rU') as fp:
    data = ''.join(fp.readlines())

data = data.split(',')
for n in range(0, len(data), 6)
    print(data[n:n+6])

必要に応じて、簡単にジェネレーターに変換できます。

def read_ugly_file(filename, delimiter=',', columns=6):
    with open(filename, 'rU') as fp:
        data = ''.join(fp.readlines())

    data = data.split(delimiter)
    for n in range(0, len(data), columns)
        yield data[n:n+columns]

for row in read_ugly_file('myfile.csv'):
    print(row)
于 2012-06-21T21:12:39.823 に答える