【问题标题】:Issues parsing text file using Python's csv module使用 Python 的 csv 模块解析文本文件时出现问题
【发布时间】:2016-07-12 07:25:42
【问题描述】:

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

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

规则:

转义字符是“\”

  • 制表符转义:\t
  • 换行符:\n
  • 反斜杠字符:\\
  • 内引号字符:\"
  • 分隔符 = |
  • 日期没有引号。
  • 数字,包括 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)

【问题讨论】:

  • 该代码正确吗?看不到 lines 已定义。
  • 你在哪里说backspace 你的意思是反斜杠吗?我很惊讶您对此有任何问题:默认情况下,csv 格式根本没有特殊的反斜杠。
  • 在你的quote_sample 中你真的想要文字\" 还是只是一个引号(Python 会给你后者)?
  • "引号字符:\n" 真的吗?确定你不是指引号字符:'"'(双引号)?

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


【解决方案1】:

您的示例中存在一些混淆,因为您没有区分输入文件中的转义和 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"']

最简单的解决方法是在测试代码中使用“原始”字符串。并且在解释输出时要小心。注意字符串定义前添加的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 模块,但如果您不知道自己在做什么,我不推荐这些。

【讨论】:

  • 感谢您到目前为止的帮助。我清理了我的描述。是的,对于引号字符,\",我关心它会删除第二个引号。理想情况下,我会将字符串变量作为单引号,内引号作为双引号,即“我读过“WSJ”,是吗? '这对于 csv 模块是否可行,或者引用我需要手动做一些事情?似乎一个解决方案可能是引用完整的,并剥离每个字段的前导和尾随引号?我没有任何分隔符双引号,但内引号会显示为一对 \" 字符串。
  • 那我的例子应该怎么解析呢?
  • 目前还不清楚你所说的\"是什么意思。在Python中\"代表一个单引号字符。但也许(?)你的意思是输入文件中有一个文字反斜杠?
  • "003261-E"|"PRO"|"公司 (\"\"ESL\"\") 是一家私人对冲基金发起人。"\r\n "0032BS-E" |"PRO"|"提供理财计划。\n\n它们位于俄亥俄州克利夫兰。"\r\n "0BS8D4-E"|"PRO"|"TBWA\\HAKUHODO, Inc."\r\n
  • 这是一个微样本,用于显示文本文件的三行。我在如何将其发布为降价时遇到问题。使用 \r\n 作为行分隔符的原始文件(来自 Windows FTP 服务器)。
猜你喜欢
  • 2019-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2018-07-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多