dln*_*385 93 python string escaping
有时当我从文件或用户那里获得输入时,我会得到一个包含转义序列的字符串.我想以与Python处理字符串文字中的转义序列相同的方式处理转义序列.
例如,假设myString定义为:
>>> myString = "spam\\neggs"
>>> print(myString)
spam\neggs
Run Code Online (Sandbox Code Playgroud)
我想要一个函数(我会称之为process)这样做:
>>> print(process(myString))
spam
eggs
Run Code Online (Sandbox Code Playgroud)
重要的是该函数可以处理Python中的所有转义序列(在上面链接的表中列出).
Python有功能吗?
Jer*_*rub 122
正确的做法是使用'string-escape'代码来解码字符串.
>>> myString = "spam\\neggs"
>>> decoded_string = bytes(myString, "utf-8").decode("unicode_escape") # python3
>>> decoded_string = myString.decode('string_escape') # python2
>>> print(decoded_string)
spam
eggs
Run Code Online (Sandbox Code Playgroud)
不要使用AST或eval.使用字符串编解码器更安全.
rsp*_*eer 107
unicode_escape 一般不起作用事实证明,string_escape或者unicode_escape解决方案通常不起作用 - 特别是,它在实际的Unicode存在的情况下不起作用.
如果你可以确定每个非ASCII字符都将被转义(并且记住,除了前128个字符之外的任何东西都是非ASCII字符串),unicode_escape它将为你做正确的事情.但是如果你的字符串中已经存在任何文字非ASCII字符,那么事情就会出错.
unicode_escape从根本上设计用于将字节转换为Unicode文本.但在许多地方 - 例如,Python源代码 - 源数据已经是Unicode文本.
这种方法可以正常工作的唯一方法是首先将文本编码为字节.UTF-8是所有文本的合理编码,因此应该可以工作,对吧?
以下示例在Python 3中,因此字符串文字更清晰,但同样的问题存在于Python 2和3上略有不同的表现形式.
>>> s = 'naïve \\t test'
>>> print(s.encode('utf-8').decode('unicode_escape'))
naïve test
Run Code Online (Sandbox Code Playgroud)
嗯,那是错的.
使用将文本解码为文本的编解码器的新推荐方法是codecs.decode直接调用.这有帮助吗?
>>> import codecs
>>> print(codecs.decode(s, 'unicode_escape'))
naïve test
Run Code Online (Sandbox Code Playgroud)
一点也不.(另外,上面是Python 2上的UnicodeError.)
该unicode_escape编解码器,尽管它的名字,原来假设所有非ASCII字节拉丁-1(ISO-8859-1)编码.所以你必须这样做:
>>> print(s.encode('latin-1').decode('unicode_escape'))
naïve test
Run Code Online (Sandbox Code Playgroud)
但那太可怕了.这限制你使用256个Latin-1字符,就像从未发明过Unicode一样!
>>> print('Ern? \\t Rubik'.encode('latin-1').decode('unicode_escape'))
UnicodeEncodeError: 'latin-1' codec can't encode character '\u0151'
in position 3: ordinal not in range(256)
Run Code Online (Sandbox Code Playgroud)
(令人惊讶的是,我们现在没有两个问题.)
我们需要做的只是将unicode_escape解码器应用于我们肯定是ASCII文本的东西.特别是,我们可以确保只将它应用于有效的Python转义序列,它们保证是ASCII文本.
计划是,我们将使用正则表达式找到转义序列,并使用函数作为参数来re.sub用它们的非转义值替换它们.
import re
import codecs
ESCAPE_SEQUENCE_RE = re.compile(r'''
( \\U........ # 8-digit hex escapes
| \\u.... # 4-digit hex escapes
| \\x.. # 2-digit hex escapes
| \\[0-7]{1,3} # Octal escapes
| \\N\{[^}]+\} # Unicode characters by name
| \\[\\'"abfnrtv] # Single-character escapes
)''', re.UNICODE | re.VERBOSE)
def decode_escapes(s):
def decode_match(match):
return codecs.decode(match.group(0), 'unicode-escape')
return ESCAPE_SEQUENCE_RE.sub(decode_match, s)
Run Code Online (Sandbox Code Playgroud)
随之而来的是:
>>> print(decode_escapes('Ern? \\t Rubik'))
Ern? Rubik
Run Code Online (Sandbox Code Playgroud)
use*_*087 27
python 3的实际正确和方便的答案:
>>> import codecs
>>> myString = "spam\\neggs"
>>> print(codecs.escape_decode(bytes(myString, "utf-8"))[0].decode("utf-8"))
spam
eggs
>>> myString = "naïve \\t test"
>>> print(codecs.escape_decode(bytes(myString, "utf-8"))[0].decode("utf-8"))
naïve test
Run Code Online (Sandbox Code Playgroud)
有关的详情codecs.escape_decode:
codecs.escape_decode 是一个字节到字节的解码器codecs.escape_decode解码ascii转义序列,例如:b"\\n"- > b"\n",b"\\xce"- > b"\xce".codecs.escape_decode 不关心或不需要知道字节对象的编码,但转义字节的编码应该与对象其余部分的编码相匹配.背景:
unicode_escape是python3的错误解决方案.这是因为unicode_escape解码转义字节,然后将字节解码为unicode字符串,但不接收有关用于第二个操作的编解码器的信息.codecs.escape_decode从这个答案中发现了"我如何在Python3中解码('string-escape')?" .正如该答案所述,目前没有为python 3记录该函数.该ast.literal_eval功能接近,但它预计字符串第一个被正确引用.
当然,Python对反斜杠转义的解释取决于字符串的引用方式(""vs r""vs u"",三引号等),因此您可能希望将用户输入包装在合适的引号中并传递给literal_eval.将它包装在引号中也会阻止literal_eval返回数字,元组,字典等.
如果用户键入要打包在字符串周围的类型的不带引号的引号,事情仍然会变得棘手.
| 归档时间: |
|
| 查看次数: |
79754 次 |
| 最近记录: |