使用Python的csv模块解析文本文件的问题

时间:2016-03-24 16:02:26

标签: csv python-3.x python-3.5

我正在尝试使用csv模块来解析特定格式的分隔文件。我正在使用Python 3.5。

格式由第三方提供,我在使用csv模块在所有情况下提供表示时遇到问题。指定为文本数据类型的任何列都具有双引号值。管道(分隔符)之间的日期和数字不会有任何引用值。问题在于,在尝试多种格式时,我要么留下一个中间双引号,要么丢失了像\ - >这样的信息。空的空间。我希望我不必为此使用正则表达式,所以如果使用csv模块可以解决这个问题,那就太好了。

规则:

转义字符是“\”

  • 标签转义:\ t
  • 换行符:\ n
  • 反斜杠字符:\\
  • 内部引用字符:\“
  • delimiter = |
  • 日期没有报价。
  • 数字,包括NaN值(空管道||)没有引号

当我尝试各种方言参数时,我似乎无法正确解析此csv文件。它要么将反斜杠转换为空格,错误放置内部引号等。是否有可能使用csv模块,或者我需要进行一些后期处理,还是创建自己的正则表达式?

import csv
import os

dialect_params = {'delimiter': '|'} # help needed here.

newline_sample = '"I went to dinner. \n Then I went to a show."'
quote_sample = '"I read the \"WSJ\", did you?"'
backslash_sample = '"Boasberg\\Wheeler Communications, Inc."'
na_sample = 'N\A'
date_sample = '2013-04-23'
number_sample = '1.3'
text_sample = '|'.join([newline_sample, quote_sample,
                        backslash_sample, na_sample,
                        date_sample, number_sample]) + '\n'

csv.reader(iter([text_sample]), **dialect_params)

1 个答案:

答案 0 :(得分:0)

您的示例中存在一些混淆,因为您没有区分输入文件中的转义和Python中的转义,不幸的是它们非常相似。您的文件似乎包含文字反斜杠,但您的Python示例却没有。请记住,在Python中,此字符串'"\""'长度为三个字符,三个都是双引号字符。

当您尝试测试代码时,这也会导致混淆。例如,如果您的代码成功地将输入中的一对反斜杠字符转换为输出中的单个反斜杠,那么当您print该输出的repr时(例如,在列表中),那么您将再次看到两个反斜杠。以下是一些示例:

# A five character string consisting of two quotes, a backslash, a
# newline and another quote
s = '"\"\\\n"'
print(s)
# prints:
#  ""\
#  "
print([s])
# prints:
#  ['""\\\n"']

对此最简单的解决方法是使用" raw"测试代码中的字符串。在解释输出时要小心。请注意字符串定义之前添加的r

# An eight character string with a lot of backslashes in
s = r'"\"\\\n"'
print(s)
# prints:
#  "\"\\\n"
print([s])
# prints:
#  ['"\\"\\\\\\n"']

好的,所以如果你清理你的Python测试,问题是什么?问题是您希望使用csv模块来解析分隔符和封闭引号。但引号存在问题。如果你告诉csv解释引号,那么它将检测字段内的转义引号并在那里停止字段。如果您随后告诉它可以对引号进行转义,则它还会将转义的换行解释为转义为n个字符。

import csv
import io

sample = r'''"ab \" cd \n ef"
"gh \\ ij \t kl"'''

# by default we have
#   doublequote = True
#   quotechar = '"'
# But this means that single quotes in the
# field are treated as ending the field
for l in csv.reader(io.StringIO(sample)):
    print(l[0])

# Setting
#   doublequote = False
#   escapechar = '\'
# handles the quote correctly but messes up the escaped newline
for l in csv.reader(io.StringIO(sample),doublequote = False,escapechar = '\\'):
    print(l[0])

# Setting
#   quotechar = None
# works correctly for the delimiters but not escaping or quoting
for l in csv.reader(io.StringIO(sample),quotechar = None):
    print(l[0])

我建议您使用csv模块正确解释分隔符,但忽略引号(如上例所示)。

然后您可以编写自己的代码来解释引用的字段。首先检查封闭引号并将其删除。然后,可以直接使用str.replace()将所有转义序列替换为所需的字符。这是一个例子:

import csv
import io

escapes = [
    (r'\t','\t'),
    (r'\n','\n'),
    (r'\\','\\'),
    (r'\"','\"'),
]

sample = r'''"ab \" cd \n ef|12"
"ij \\ kl \t mn"|"o"'''

for l in csv.reader(io.StringIO(sample),delimiter = '|',quotechar = None):
    l = [f if f[0] != '"' else f[1:-1] for f in l]
    for old,new in escapes:
        l = [f.replace(old,new) for f in l]
    print(l)

最后,请注意,这是一种很好的直接方式,但它的表现不会很好。有些可能的解决方案。例如,您可以使用ast.literal_eval,因为这些转义符与Python转义符兼容,或者您​​甚至可以使用codecs模块,但如果您不知道我不推荐这些转义符你正在做什么。