【问题标题】:How to find/replace non printable / non-ascii characters using Python 3?如何使用 Python 3 查找/替换不可打印/非 ascii 字符?
【发布时间】:2019-07-02 13:56:24
【问题描述】:

我有一个文件,.csv 文件中的某些行由于行中某些字段中的时髦字符而阻塞了数据库导入。

我搜索并找到了有关如何在 Python 3 中替换非 ascii 字符的文章,但没有任何效果。

当我在 vi 中打开文件并执行 :set list 时,在不应存在的行尾有一个 $,而在下一行的开头有一个 ^I^I。这两行应该是一条连接线,并且那里没有 ^I。我知道 $ 是行 '\n' 的结尾,并尝试替换它们,但没有任何效果。

我不知道 ^I 代表什么,可能是一个制表符。


我试过这个功能没用:

def remove_non_ascii(text):
    new_text = re.sub(r"[\n\t\r]", "", text)
    new_text = ''.join(new_text.split("\n"))
    new_text = ''.join([i if ord(i) < 128 else ' ' for i in new_text])
    new_text = "".join([x for x in new_text if ord(x) < 128])
    new_text = re.sub(r'[^\x00-\x7F]+', ' ', new_text)
    new_text = new_text.rstrip('\r\n')
    new_text = new_text.strip('\n')
    new_text = new_text.strip('\r')
    new_text = new_text.strip('\t')
    new_text = new_text.replace('\n', '')
    new_text = new_text.replace('\r', '')
    new_text = new_text.replace('\t', '')
    new_text = filter(lambda x: x in string.printable, new_text)
    new_text = "".join(list(new_text))

    return new_text

有什么工具可以准确地告诉我这个有问题的字符是什么,然后找到一种方法来替换它?

我像这样打开文件(.csv 保存为 UTF-8)

f_csv_in = open(csv_in, "r", encoding="utf-8")

下面是两行,应该是有问题的非 ascii 字符可见的一行。

这两行应该是一行。注意第 37 行末尾的 $,第 38 行以 ^I^I 开头。

vi 显示的部分问题在于,我不希望在第 37 行有一个新行 $。这应该是一行。

37 Cancelled,01-19-17,,basket,00-00-00,00-00-00,,,,98533,SingleSource,,,17035 Cherry Hill Dr,"L/o 1-19-17 @ 11:45am$
38 ^I^IVictorville",SAN BERNARDINO,CA,92395,,,,,0,,,,,Lock:6111 ,,,No,No,,0.00,0.00,No,01-19-17,0.00,0.00,,01-19-17,00-00-00,,provider,,,Unread,00-00-00,,$

【问题讨论】:

  • 如果您使用的是 Windows,^ 用于 escape characters.,而$ 通常表示行尾,例如。在正则表达式中。可能是您的文件是“管道分隔的”并且前两个字段为空吗?你用的是什么编辑器,能不能禁用格式化字符的显示?
  • 文件中的字段以逗号分隔。文件中有 150K 行,除了 81 行坏行,一切都很好。当我在 IDE 中打开时,81 条坏行中的每一行都分为两行(参见上面的 37、38)。上面的示例中给出了两条这样的行(应该是一条)。如果任何字段为空,那没关系,逗号(分隔符)之间没有任何内容。我不确定禁用格式化字符的显示是什么意思。
  • 我想删除任何转义字符,例如 ^I,并且我想删除上面第 37 行末尾的新行 $ 字符。如果有代码将删除 ^I 转义字符和行中间的换行符,如第 37 行,因此最终第 37 行和第 38 行是一行,请分享。我尝试了原始帖子中列出的所有选项来删除这两个选项。

标签: python python-3.x csv non-ascii-characters


【解决方案1】:

删除非 ascii 字符的简单方法是:

new_text = "".join([c for c in text if c.isascii()])

注意:如果您从文件中读取此文本,请确保使用正确的编码读取它

【讨论】:

  • 我尝试了该代码 sn-p,但没有成功。 .csv 文件保存为 UTF-8,我是这样打开的。 f_csv_in = open(csv_in, "r")
  • 试试f_csv_in = open(csv_in, "r", encoding='utf-8')
  • 到目前为止,使用 encoding='utf-8' 打开时没有这样的运气。在 .csv 文件的 150K 行中,有 162 行中有一些字符会挂起,其他近 150K 行都可以。
  • 你用的是linux吗?如果您运行file csv_in,报告的编码是什么?
  • 我在 Windows 下使用 cygwin。我在cygwin下使用Python。该文件使用 Excel 以 UTF-8 .csv 格式保存。它在 Python 中使用 encoding='utf-8' 打开
【解决方案2】:

对于不可打印字符,内置的字符串模块有一些过滤不可打印或非ascii字符的方法,例如。具有isprintable() 功能。
下面介绍了一种一次过滤整个字符串的简洁方法

>>> import string
>>>
>>> str1 = '\nsomestring'
>>> str1.isprintable()
False
>>> str2 = 'otherstring'
>>> str2.isprintable()
True
>>>
>>> res = filter(lambda x: x in string.printable, '\x01mystring')
>>> "".join(list(res))
'mystring'

这个问题过去在 SO 上有一些 discussion,但是有很多方法可以做,所以我理解它可能会让人困惑,因为你可以使用从正则表达式到 str.translate() 的任何东西

可以做的另一件事是查看Unicode Categories,并根据您需要的符号集过滤掉您的数据。

【讨论】:

  • 根据您的cmets,我在方法中添加了这两行:remove_non_ascii(text),但没有成功。 new_text = filter(lambda x: x in string.printable, new_text) new_text = "".join(list(new_text))```
  • 您可以在其他文本编辑器中打开您的文件吗?人物还在吗?您能否提供几个示例行来处理真实数据?
  • 我可以在文本编辑器中打开文件,我可以在 vi 中打开它。当我在 vi 中键入 :set list 时,我看到在该行的末尾有一个 $,不应该有。它下面的行以 ^I(控件 I)开头,其中两个连续。这两行应该连接到一行,第一行的末尾没有 $ ,并且在该行的任何点都没有 ^I^I 。我可以提供一条线来使用,但是如何?
  • Vi 应该在您键入 :set list 以表示行尾时显示 $,因此这不是错误。那里没有任何“真实”字符可以删除,它只是 vi 行尾样式。至于^|,你的csv文件是用什么分隔的?
  • 下面是两行,应该是非 ascii 字符可见的一行。这两行应该是一行。注意第 37 行末尾的 $,第 38 行以 ^I^I 开头。 vi 显示的问题是,在第 37 行有一个新行 $ ,我不希望它出现。应该是一行。 37 Cancelled,01-19-17,,basket,00-00-00,00-00-00,,,,98533,SingleSource,,,17035 Cherry Hill Dr,"L/o 1-19-17 @ 11:45am$ 38 ^I^IVictorville",SAN BERNARDINO,CA,92395,,,,,0,,,,,Lock:6111 ,,,No,No,,0.00,0.00,No,01-19-17,0.00,0.00,,01-19-17,00-00-00,,provider,,,Unread,00-00-00,,$
【解决方案3】:

看起来好像您有一个包含引用值的 csv 文件,即嵌入的逗号或换行符等必须用引号括起来的值,以便 csv 阅读器正确处理它们。

如果您查看示例数据,您会看到第一行末尾有一个左双引号但没有右双引号,第二行有一个没有左双引号的右双引号,表明引号包含一个值嵌入的换行符。

行被分成两部分的事实可能是用于查看它们的应用程序的人工制品,或者是处理它们的代码:如果软件不理解 csv 引用,它将假定每个换行符表示一个新行.

目前尚不清楚这会在数据库中造成什么问题,但引号字符(尤其是不匹配的引号)很可能会导致问题,尤其是在插入前数据未正确转义的情况下。

这个 sn-p 重写文件,删除嵌入的逗号、换行符和制表符,并指示编写者不要引用任何值。如果找到需要转义的值,它将失败并显示错误消息_csv.Error: need to escape, but no escapechar set。根据您的数据,您可能需要调整正则表达式模式。

with open('lines.csv') as f, open('fixed.csv', 'w') as out:
    reader = csv.reader(f)
    writer = csv.writer(out, quoting=csv.QUOTE_NONE)
    for line in reader:
        new_row = [re.sub(r'\t|\n|,', ' ', x) for x in line]
        writer.writerow(new_row)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 1970-01-01
    相关资源
    最近更新 更多