【问题标题】:Python removing invalid ascii charactersPython删除无效的ascii字符
【发布时间】:2016-12-07 10:43:11
【问题描述】:

我最近编写了一个脚本来从 pdf 中提取所有书签并将它们保存在 docx 文件中。它适用于 90% 的文件,但不幸的是有些文件似乎存在 unicode 问题。

我在这样的列表中获得书签:

[[u'3. Mechatronik f\xfcr Doppelkupplungsgetriebe, Sicherungshalter B, Sicherung 14 auf Sicherungshalter C', 2],
[u'4. Geber f\xfcr Getriebeeingangsdrehzahl, Hydraulikdruckgeber 1 f\xfcr automatisches Getriebe, Magnetventil 2, Magnetventil \x04, Magnetventil 5', 2],
[u'5. W\xe4hlhebel, Schalter f\xfcr W\xe4hlhebel in P gesperrt, Magnet f\xfcr W\xe4hlhebelsperre', 2], 
[u'6. W\xe4hlhebel, Geber 2 f\xfcr Antriebswellendrehzahl, W\xe4hlhebel-Positionsanzeige', 2]]

当我尝试运行该函数时,我得到了错误:

ValueError('All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters',)

代码:

from docx import Document

list1 = [[u'3. Mechatronik f\xfcr Doppelkupplungsgetriebe, Sicherungshalter B, Sicherung 14 auf Sicherungshalter C', 2],
    [u'4. Geber f\xfcr Getriebeeingangsdrehzahl, Hydraulikdruckgeber 1 f\xfcr automatisches Getriebe, Magnetventil 2, Magnetventil \x04, Magnetventil 5', 2],
    [u'5. W\xe4hlhebel, Schalter f\xfcr W\xe4hlhebel in P gesperrt, Magnet f\xfcr W\xe4hlhebelsperre', 2],
    [u'6. W\xe4hlhebel, Geber 2 f\xfcr Antriebswellendrehzahl, W\xe4hlhebel-Positionsanzeige', 2]]

def save_docx(list1):
document = Document('default.docx')
file = open("Error_Log.txt", 'w')
for i in list1:
    try:
        p = document.add_paragraph()
        p.add_run(i[0]).bold = True
    except Exception as e:
        file.write(repr(e) + '\n')
file.close()
document.save('Bookmarks.docx')

save_docx(list1)

我猜问题出在\x0,但我不知道如何在不破坏整个文档的情况下删除这样的部分。 我已经尝试了不同的编码以及我可以在网上找到的任何其他东西,但到目前为止没有任何效果。

任何帮助将不胜感激!

【问题讨论】:

  • 你试过了吗? i[0].encode('utf-8') 基于stackoverflow.com/questions/5760936/… 中的讨论
  • 是的,我尝试以各种方式去编码和编码,例如i[0].encode('ascii' 'ignore') 等没有任何效果。还查看了可能有帮助但到目前为止没有运气的库。
  • 来自@jackmorris 的好回答。难道是编码后控制字符仍在字符串中?因此最终结果将是相同的(错误“无控制字符”)

标签: python unicode ascii


【解决方案1】:

您的假设似乎是正确的:\x04 是一个控制字符,并且您的错误消息明确指出不允许控制。

您可以在将字符串添加到文档之前过滤掉字符串中的控制字符,这应该可以解决您的问题。这可以通过 Python 的unicodedata module,特别是unicodedata.category 来完成。您要排除的类别以“C”开头(来自http://www.unicode.org/reports/tr44/#GC_Values_Table),其中包含所有控制字符。

以下应该可以代替您当前的add_run 行:

line = filter(lambda c: unicodedata.category(c)[0] != 'C', i[0])
p.add_run(line).bold = True

顺便说一句,在 unicode 字符串中包含 unicode 字符的典型方法是使用 \uXXXX,而不是 \xXX(其中 XXXX 是 unicode 代码点的十六进制)。

【讨论】:

  • unicodedata 为\x04 返回的类别是Cc,而不是C。而且我不会说\uXXXX 表示法是“典型”方式,\xXX\u00XX\U000000XX 对于低于 256 的代码点没有区别,并且 python 本身总是使用最短的可能形式,例如ascii("\U000000FF")(或python2中的repr(u"\U000000FF"))给出\xff
  • 类别“C”包括“Cc”,以及“Cf”,它是一个格式控制字符。
  • 另一方面,“典型”可能是错误的词,但我认为将 unicode 字符指定为代码点而不是字节值更有意义,特别是当您超过 256 时。您'说得对,它对低值代码点没有影响。
  • 惊人的答案!非常感谢!我对 python 很陌生,这需要我很长时间才能弄清楚。
  • 是的,但是您正在比较unicodedata.category(c) != 'C',如果返回的类别是Cc,则将失败,因此不过滤,您只需要比较第一个字符。由于 OP 可能没有键入该字符串,而是从某处复制其表示,因此建议更改转义序列似乎有点过分。我更喜欢 python 使用最短形式来转义代码点的方式,它只是表达数值的另一种方式。相同的转义形式可用于表示不同上下文中的字节值与 unicode 无关。
猜你喜欢
  • 2014-08-12
  • 2019-03-03
  • 2018-04-20
  • 2016-07-28
  • 1970-01-01
  • 2012-05-17
  • 2016-01-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多