y3d*_*3di 14 python xml unicode text lxml
我在我的python程序中收到此错误: ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters
这个问题,来自/ dev/random的随机文本引发了lxml中的错误:所有字符串必须是XML兼容的:Unicode或ASCII,没有NULL字节,解释了这个问题.
解决方案是过滤掉某些字节,但我很困惑如何去做.
有帮助吗?
编辑:对不起,如果我没有提供有关该问题的足够信息.字符串数据来自外部api查询,我无法控制数据的格式.
Joh*_*hin 22
正如链接问题的答案所说,XML标准将有效字符定义为:
Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
Run Code Online (Sandbox Code Playgroud)
将其翻译成Python:
def valid_xml_char_ordinal(c):
codepoint = ord(c)
# conditions ordered by presumed frequency
return (
0x20 <= codepoint <= 0xD7FF or
codepoint in (0x9, 0xA, 0xD) or
0xE000 <= codepoint <= 0xFFFD or
0x10000 <= codepoint <= 0x10FFFF
)
Run Code Online (Sandbox Code Playgroud)
然后,您可以根据需要使用该功能,例如
cleaned_string = ''.join(c for c in input_string if valid_xml_char_ordinal(c))
Run Code Online (Sandbox Code Playgroud)
mli*_*ner 11
另一种比上面的答案快得多的方法是使用正则表达式,如下所示:
re.sub(u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+', '', text)
Run Code Online (Sandbox Code Playgroud)
与上面的答案相比,我的测试速度提高了10倍以上:
import timeit
func_test = """
def valid_xml_char_ordinal(c):
codepoint = ord(c)
# conditions ordered by presumed frequency
return (
0x20 <= codepoint <= 0xD7FF or
codepoint in (0x9, 0xA, 0xD) or
0xE000 <= codepoint <= 0xFFFD or
0x10000 <= codepoint <= 0x10FFFF
);
''.join(c for c in r.content if valid_xml_char_ordinal(c))
"""
func_setup = """
import requests;
r = requests.get("https://stackoverflow.com/questions/8733233/")
"""
regex_test = """re.sub(u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+', '', r.content)"""
regex_setup = """
import requests, re;
r = requests.get("https://stackoverflow.com/questions/8733233/")
"""
func_test = timeit.Timer(func_test, setup=func_setup)
regex_test = timeit.Timer(regex_test, setup=regex_setup)
print func_test.timeit(100)
print regex_test.timeit(100)
Run Code Online (Sandbox Code Playgroud)
输出:
> 2.63773989677
> 0.221401929855
Run Code Online (Sandbox Code Playgroud)
因此,理解这一点,我们正在做的是下载此网页一次(您当前正在阅读的页面),然后在其内容100X上运行功能技术和正则表达式技术.
使用功能方法大约需要2.6秒.
使用正则表达式方法大约需要0.2秒.
更新:正如评论中所指出的,此答案中的正则表达式先前删除了一些字符,这些字符应该在XML中允许.这些角色包括补充多语言平面中的任何内容,其中包括楔形文字,象形文字和(奇怪的)表情符号等古代文字.
正确的正则表达式现在在上面.未来的快速测试是使用re.DEBUG,打印:
In [52]: re.compile(u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+', re.DEBUG)
max_repeat 1 4294967295
in
negate None
range (32, 55295)
literal 9
literal 10
literal 13
range (57344, 65533)
range (65536, 1114111)
Out[52]: re.compile(ur'[^ -\ud7ff\t\n\r\ue000-\ufffd\U00010000-\U0010ffff]+', re.DEBUG)
Run Code Online (Sandbox Code Playgroud)
我为错误道歉.我只能提供我在其他地方找到这个答案并把它放在这里.这是别人的错误,但我传播了它.我真诚地向受影响的人道歉.
更新2,2017-12-12:我从一些OSX用户那里了解到,这段代码不能用于所谓的Python的窄版本,这显然是OSX有时会有的.您可以通过运行来检查import sys; sys.maxunicode.如果它打印65535,则在安装"wide build"之前,此处的代码将不起作用.在这里查看更多相关信息.