在熊猫中读取带有双“双引号”和嵌入式逗号的CSV文件

时间:2019-10-10 14:31:33

标签: python pandas csv

我需要在Pandas中读取CSV文件,该文件的数据格式如下(其中一个字段用双“双引号”表示)

"column1","column2","column3","column4"
"10",""AB"","ABCD","abcd"
"11",""CD,E"","CDEF","abcd"
"12",""WER"","DEF,31","abcd"

我希望正确解析的数据帧像

column1  column2  column3   column4
10       AB       ABCD      abcd
11       "CD,E"   CDEF      abcd
12       WER      "DEF,31"  abcd

我尝试使用

df= pd.read_csv('sample.txt',quotechar='""', quoting=csv.QUOTE_ALL)

df= pd.read_csv('sample.txt',quotechar='"', quoting=csv.QUOTE_ALL)

但是得到

TypeError: "quotechar" must be a 1-character string

pandas.errors.ParserError: Error tokenizing data. C error: Expected 4 fields in line 3, saw 5

有没有一种方法可以让我按原样读取此文件,而无需预处理并删除数据中的双“双引号”?

column2没有逗号时,我可以读取带有一些额外引号的数据,这些引号可以在以后的处理步骤中替换。仅当column2带有逗号时,我才遇到解析问题。

3 个答案:

答案 0 :(得分:1)

我不确定熊猫是否可以单独执行此操作,因为您的数据中同时包含未转义的分隔符和引号。

但是,在使用正则表达式修改数据后,您应该能够通过转义字段中的引号将其解析。

import re
from io import StringIO

data = """
"column1","column2","column3","column4"
"10",""AB"","ABCD","abcd"
"11",""CD,E"","CDEF","abcd"
"12",""WER"","DEF,31","abcd"
"""

data = re.sub('(?<!^)"(?!,")(?<!,")(?!$)', '\\"', data, flags=re.M)

pd.read_csv(StringIO(data), escapechar='\\')

如果您正在读取文件,则:

with open('path/to/csv', 'r') as f:
    data = re.sub('(?<!^)"(?!,")(?<!,")(?!$)', '\\"', f.read(), flags=re.M)
    df = pd.read_csv(StringIO(data), escapechar='\\')

正则表达式将查找不在每行开头(?<!^)或结尾(?!$)处的引号,并查找不在开头(?<!,")和结尾{{1中的引号}}的每个字段

答案 1 :(得分:1)

这应该为您解决问题

df =pd.read_csv("so.txt",encoding='utf-8', names=["column1","column2","column3","column4"],sep='",',header=0,quoting=csv.QUOTE_ALL)

答案 2 :(得分:0)

预处理不一定是坏事。如果使用系统管道完成,则不会增加太多开销(如上面带有 StringIO 的开销)。它还可以节省大量时间来解决一些已知问题(例如 DOS CR、EOF 处没有 EOL、中间有 NULL 字节等,具体取决于您的系统)。

对于这种情况+一些其他常见问题,例如额外的引号、空格、逗号、嵌入的逗号。虽然 pandas 确实有一个参数 doublequote,但它不够灵活。

使用系统管道,对于 Linux 上的大文件应该很有效

import os
df = pd.read_csv(
  os.popen('sed -r "s/^\s+|(^[,[:space:]]*|\s*)(#.*)?$//g; s/\s+,/,/g; s/\\"\\"/\\"/g" %s' % fname),
    quotechar='"', skipinitialspace=True)

或:使用 python 管道

import re
from io import StringIO
with open(fname) as f:
  data = re.sub('""', '"', re.sub('[ \t]+,', ',',
    re.sub('^[ \t]+|(^[ \t,]*|[ \t]*)(#.*)?$', '', f.read(), flags=re.M)))
  df = pd.read_csv(StringIO(data), quotechar='"', skipinitialspace=True)

带有评论和问题的输入文件

a, b, c, d         # header w/ trailing spaces
,, ,,,,            # commas + spaces, no data
# extra space before data
  1, 2, 3.5, 4k     
3, " 5 " , 7.6, "n, m" # extra spaces, comma inside
10, "20" , 30.5, w z
40, 60, 75, ""x, q""   # double quoting

输出:

    a   b     c     d
0   1   2   3.5    4k
1   3   5   7.6  n, m
2  10  20  30.5   w z
3  40  60  75.0  x, q

现在干净且格式正确:

a int64
b int64
c float64
d object

list(df['d']):  ['4k', 'n, m', 'w z', 'x, q']