【问题标题】:Python: using re.sub for ascii numbers coded as &#number;Python:将 re.sub 用于编码为 &#number; 的 ascii 数字
【发布时间】:2014-07-10 00:35:26
【问题描述】:

我的文本中有一些奇怪的字符。例如,可能会出现“éxâmplë”这个词。但它并没有这样显示,而是显示为‚xƒmpl‰。幸运的是,这些数字是 ASCII 编码的,所以我可以使用 chr()。所以,我想用chr(number) 替换&#<number>;

我开始为此使用re 模块,但由于我对此没有那么丰富的经验,所以我不知道该怎么做。下面是我的尝试,但当然,代码尝试在执行re.sub() 部分之前将int() 部分转换为int,从而引发ValueError。我怎样才能正确地做到这一点?

sentence = "This is an ‚xƒmpl‰."
chrpatt = "&#([0-9]{3});"
sentence = re.sub(chrpatt, chr(int("\g<1>")), sentence)
print sentence

【问题讨论】:

  • 您从哪里获得这些数据? HTML 使用 DOS 代码页对变音字符进行编码是非常不寻常的。
  • 数据是从使用urllib2的网站读取的。

标签: python regex ascii


【解决方案1】:

这里不需要使用正则表达式。

为此有一个完整的库,称为HTMlParser

示例:

>>> import HTMLParser
>>> h = HTMLParser.HTMLParser()
>>> h.unescape("This is an &#130;x&#131;mpl&#137;.")
u'This is an \x82x\x83mpl\x89.'

以防万一之前不清楚:

>>> chr(130)
'\x82'
>>> chr(131)
'\x83'
>>> chr(137)
'\x89'

不要重新发明轮子

【讨论】:

  • @Lewistrick 你一定是在开玩笑吧? print x 其中x 是结果。例如:x = h.unescape(s)sigh
  • @Lewistrick "It doesn't work" 是对所发生情况的非常简洁的描述......
  • 对不起,这确实是一种非常直率的表达方式。我的意思是:print u'This is an \x82x\x83mpl\x89.' 返回一个UnicodeDecodeError(字符映射到 )。
  • @Lewistrick 由于您的示例使用 CP437 或 CP850,u'This is an \x82x\x83mpl\x89.' 是错误的。相反,u'This is an \xe9x\xe2mpl\xeb.' 是正确的。
【解决方案2】:

int("\g&lt;1&gt;") 在此处为您提供 ValueError。 int 是 int 构造函数。如果你给这个构造函数一个字符串,它期望找到一个代表数字的字符串。显然,字符串“\g”看起来不像数字的表示。

在您的情况下,re.sub 的第二个参数应该是一个函数,它将接受找到的匹配并对其进行转换。

引用自 python 文档 https://docs.python.org/3.4/library/re.html#re.sub

re.sub(pattern, repl, string, count=0, flags=0)

...

如果 repl 是一个函数,它会在每个不重叠的模式出现时调用。该函数采用单个匹配对象参数,并返回替换字符串。例如:

【讨论】:

    【解决方案3】:

    sub()可以使用callable参数:

    >>> import re
    >>> sentence = "This is an &#130;x&#131;mpl&#137;."
    >>> chrpatt = "&#([0-9]{3});"
    >>> def rpl(m): return chr(int(m.group(1)))
    >>> re.sub(chrpatt, rpl, sentence)
    'This is an \x82x\x83mpl\x89.'
    >>> print re.sub(chrpatt, rpl, sentence)
    This is an éxâmplë.
    

    显然,数据被编码为 DOS 代码页之一(437 或 850):在我家的 Linux 系统上,我必须这样做

    >>> print re.sub(chrpatt, lambda m: chr(int(m.group(1))) , sentence).decode("cp437")
    This is an éxâmplë.
    >>> re.sub(chrpatt, lambda m: chr(int(m.group(1))) , sentence).decode("cp437")
    u'This is an \xe9x\xe2mpl\xeb.'
    

    为了得到正确的输出。

    这里发生了什么?

    对于每个匹配,给定的函数都会传递匹配对象,并应该返回替换字符串。

    所以我们只是这样做 - 从匹配中提取数字并执行您建议的步骤。

    【讨论】:

    • 这完全一样,对吧? print re.sub(chrpatt, lambda m: chr(int(m.group(1))) , sentence)
    • @Lewistrick 是的。通常情况下,我会写这个,但不得不测试一下就忘记了。
    • &gt;&gt;&gt; print "This is an \x82x\x83mpl\x89." This is an �x�mpl�.
    • @JamesMills 取决于您使用的编码。
    猜你喜欢
    • 1970-01-01
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 2013-02-28
    • 2013-11-04
    • 2019-02-04
    相关资源
    最近更新 更多