在python中过滤掉某些字节
我在python程序中遇到此错误:在python中过滤掉某些字节,python,xml,text,unicode,lxml,Python,Xml,Text,Unicode,Lxml,我在python程序中遇到此错误:ValueError:所有字符串必须与XML兼容:Unicode或ASCII,没有空字节或控制字符 这个问题,解释了这个问题 解决方案是过滤掉某些字节,但我不知道该怎么做 有什么帮助吗 编辑:如果我没有提供足够的关于这个问题的信息,很抱歉。字符串数据来自外部api查询,我无法控制该查询的数据格式。正如对链接问题的回答所述,XML标准将有效字符定义为: Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFF
ValueError:所有字符串必须与XML兼容:Unicode或ASCII,没有空字节或控制字符
这个问题,解释了这个问题
解决方案是过滤掉某些字节,但我不知道该怎么做
有什么帮助吗
编辑:如果我没有提供足够的关于这个问题的信息,很抱歉。字符串数据来自外部api查询,我无法控制该查询的数据格式。正如对链接问题的回答所述,XML标准将有效字符定义为:
Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
将其转换为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
)
您可以参考本网站上的解决方案: 这个解决方案对我有效。你也可能需要考虑John Machin的解决方案。
祝你好运 我认为这太苛刻/过分了,速度似乎慢得令人痛苦,但我的程序仍然很快,在努力理解出了什么问题后(即使在我尝试实现@John的cleaned_字符串实现之后),我只是使用以下(Python 2.7)修改了他的答案,以清除ASCII不可打印:
我不确定我对更好的选择做错了什么,但我只是想继续 另一种比上述答案快得多的方法是使用正则表达式,如下所示:
re.sub(u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+', '', text)
与上面的答案相比,我的测试速度快了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)
因此,有意义的是,我们正在做的是下载这个网页一次(你当前正在阅读的页面),然后在其内容上运行函数技术和正则表达式技术各100倍
使用函数法大约需要2.6秒。使用regex方法大约需要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)
我为这个错误道歉。我只能说,我在别处找到了这个答案,并把它放在这里。这是别人的错误,但我传播了它。我向任何受此影响的人表示诚挚的歉意
更新22017-12-12:我从一些OSX用户那里了解到,这段代码在所谓的Python狭义版本上不起作用,而OSX有时显然会这样做。您可以通过运行
import sys;sys.maxunicode
。如果它打印65535,那么这里的代码在您安装“宽版本”之前无法工作 你是否也有你所指问题中输入的随机数据?这看起来可能有用。不幸的是,数据来自外部api,很少抛出错误。所以我无法重现导致错误的条件。我必须等到情况相同后才能测试这个解决方案。感谢您的回复,我对python还比较陌生,了解您的解决方案的实现(以及它如何解决我的问题)将使我有机会更好地理解该语言。@y3di:在您等待错误再次发生时,您可能希望更改代码以捕获错误,并将有问题的XML文档写入日志文件。这样,您就可以准确地找出非法字符是什么,并决定是删除它们还是替换其他字符更合适。在任何情况下,你的问题(实际上:如何从XML文档中过滤出非法字符)已经被回答,并且你应该考虑接受它(点击答案左边的“滴答”)。出于属性的目的,我只是在这里插入了一个要点,其中有一个代码,用于从字符串中过滤这个字符,因为我最近不得不使用它。谢谢你的回答。我发现lxml.builder.E不接受字符“\xa9”,但函数没有过滤掉它从lxml.builder导入E
E('a','\xa9')
值错误:所有字符串必须是XML兼容的:Unicode或ASCII,没有空字节或控制字符'.join(c表示'\xa9'中的c,如果有效的话)
'\xa9'您可以使用字节。translate()
删除/替换不在字符串中的字节。可打印
。与@John Machin的解决方案不同;它不适用于任意Unicode文本。您确定正则表达式按预期工作吗?我相信最后两个F
字母没有被解析为\u
转义的一部分。在python控制台中试试这个:print(u'\u10ffff')
然后这个:print(u'\u10ffzz')
你是对的,如果删除代码点在65536和1114111之间的unicode,肯定会导致数据擦除。我已经更新了答案。这会抛出一个错误radars\u string=re.sub(u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+,'',radars\u string)文件“/System/libraries/Python.framework/Versions/2.7/lib/python2.7/re.py”,第155行,在sub返回(模式、标志)文件中“/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/re.py”,第251行,在_compileraise error中,v#无效的表达式sre_常量。错误:错误的字符范围
我怀疑您可能有一个“窄”的Python构建?不是正的,但很容易检查使用宽的构建是否修复了问题:链接已断开
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)
> 2.63773989677
> 0.221401929855
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)