在引用的 csv 中匹配未转义的引号

Posted

技术标签:

【中文标题】在引用的 csv 中匹配未转义的引号【英文标题】:Match unescaped quotes in quoted csv 【发布时间】:2017-09-23 05:41:23 【问题描述】:

我查看了几个标题相似的 Stack Overflow 帖子,但没有一个被接受的答案对我有用。

我有一个 CSV 文件,其中每个“单元格”数据都用逗号分隔并用引号括起来(包括数字)。每行以换行符结束。

某些文本“单元格”中有引号,我想使用正则表达式找到它们,以便可以正确转义它们。

示例行:

"0","0.23432","234.232342","data here dsfsd hfsdf","3/1/2016",,"etc","E 60"","AD"8"\n

我想只匹配E 60"AD"8 中的",而不是任何其他"

我可以使用什么(最好是 Python 友好的)正则表达式来执行此操作?

【问题讨论】:

regex101.com/r/VxEXf2/3 感谢您的回复!这很接近,但我只想匹配那些内部引号字符以便我可以替换它们(例如,我不想替换 E 60 部分。我想我还需要字符串的其余部分是比限制其他字符串中的单个数字和字母更灵活(请参阅更新的原始帖子示例)。 你能更新你想要的匹配吗 匹配是一样的——只是内部的"字符。我认为这样做了,尽管可能效率不高:r'(?<!^)(?<!,)\"(?!,|$)' regex101.com/r/qbPgxJ/1 【参考方案1】:

编辑:使用来自@sundance 的正则表达式进行了更新,以避免行首和换行。

您可以尝试仅替换不在逗号、行首或换行符旁边的引号:

import re

newline = re.sub(r'(?<!^)(?<!,)"(?!,|$)', '', line)

【讨论】:

成功了!我先使用re.compile 编译它,然后在编译的正则表达式字符串上使用sub 方法。能够在大约 3-4 分钟内清理我的 4M 行文件。【参考方案2】:

这里没有使用正则表达式,而是使用 Python 的字符串函数仅查找和转义字符串左右引号之间的引号。

它使用字符串的.find().rfind() 方法来查找周围的" 字符。然后,它会替换出现在外引号内的任何其他 " 字符。这样做不会假设周围的引号在 , 分隔符之间的位置,因此它不会改变任何周围的空格(例如,它会在每行的末尾保留 '\n' 原样)。

def escape_internal_quotes(item):
    left = item.find('"') + 1
    right = item.rfind('"')
    if left < right:
        # only do the substitution if two surrounding quotes are found
        item = item[:left] + item[left:right].replace('"', '\\"') + item[right:]
    return item

line = '"0","0.23432","234.232342","data here dsfsd hfsdf","3/1/2016",,"etc","E 60"","AD"8"\n'
escaped = [escape_internal_quotes(item) for item in line.split(',')]
print(repr(','.join(escaped)))

导致:

'"0","0.23432","234.232342","data here dsfsd hfsdf","3/1/2016",,"etc","E 60\\"","AD\\"8"\n'

【讨论】:

这可能会得到相同的答案,但它的效率肯定低于正则表达式引擎。我需要在 4M 行上执行此操作,因此性能将是一个问题 @sundance 感谢您的反馈。我没有意识到你的文件有多大。我运行了计时,发现非正则表达式解决方案大约需要两倍的时间(您的文件大约需要 8 分钟)。

以上是关于在引用的 csv 中匹配未转义的引号的主要内容,如果未能解决你的问题,请参考以下文章

具有奇怪行为的正则表达式:将字符串与反向引用匹配以允许转义以及单引号和双引号

如何阅读包含转义引号的引用文本

将数据从 SQL Server Express 导出到 CSV(需要引用和转义)

Python CSV 解析,转义引号字符

正确转义 CSV 中的双引号

使用 Python 的 csv.reader 处理转义引号