【问题标题】:Python Unicode Regular ExpressionPython Unicode 正则表达式
【发布时间】:2009-07-22 23:57:26
【问题描述】:

我使用的是 python 2.4,但遇到了 unicode 正则表达式的一些问题。我试图为我的问题整理一个非常清晰简洁的例子。看起来 Python 如何识别不同的字符编码存在一些问题,或者我的理解存在问题。非常感谢您观看!

#!/usr/bin/python
#
# This is a simple python program designed to show my problems with regular expressions and character encoding in python
# Written by Brian J. Stinar
# Thanks for the help! 

import urllib # To get files off the Internet
import chardet # To identify charactor encodings
import re # Python Regular Expressions 
#import ponyguruma # Python Onyguruma Regular Expressions - this can be uncommented if you feel like messing with it, but I have the same issue no matter which RE's I'm using

rawdata = urllib.urlopen('http://www.cs.unm.edu/~brian.stinar/legal.html').read()
print (chardet.detect(rawdata))
#print (rawdata)

ISO_8859_2_encoded = rawdata.decode('ISO-8859-2') # Let's grab this as text
UTF_8_encoded = ISO_8859_2_encoded.encode('utf-8') # and encode the text as UTF-8
print(chardet.detect(UTF_8_encoded)) # Looks good

# This totally doesn't work, even though you can see UNSUBSCRIBE in the HTML
# Eventually, I want to recognize the entire physical address and UNSUBSCRIBE above it
re_UNSUB_amsterdam = re.compile(".*UNSUBSCRIBE.*", re.UNICODE)
print (str(re_UNSUB_amsterdam.match(UTF_8_encoded)) + "\t\t\t\t\t--- RE for UNSUBSCRIBE on UTF-8")
print (str(re_UNSUB_amsterdam.match(rawdata)) + "\t\t\t\t\t--- RE for UNSUBSCRIBE on raw data")

re_amsterdam = re.compile(".*Adobe.*", re.UNICODE)
print (str(re_amsterdam.match(rawdata)) + "\t--- RE for 'Adobe' on raw data") # However, this work?!?
print (str(re_amsterdam.match(UTF_8_encoded)) + "\t--- RE for 'Adobe' on UTF-8")

'''
# In additon, I tried this regular expression library much to the same unsatisfactory result
new_re = ponyguruma.Regexp(".*UNSUBSCRIBE.*")
if new_re.match(UTF_8_encoded) != None:
   print("Ponyguruma RE matched! \t\t\t--- RE for UNSUBSCRIBE on UTF-8")
else:
   print("Ponyguruma RE did not match\t\t--- RE for UNSUBSCRIBE on UTF-8")

if new_re.match(rawdata) != None:
   print("Ponyguruma RE matched! \t\t\t--- RE for UNSUBSCRIBE on raw data")
else:
   print("Ponyguruma RE did not match\t\t--- RE for UNSUBSCRIBE on raw data")

new_re = ponyguruma.Regexp(".*Adobe.*")
if new_re.match(UTF_8_encoded) != None:
   print("Ponyguruma RE matched! \t\t\t--- RE for Adobe on UTF-8")
else:
   print("Ponyguruma RE did not match\t\t\t--- RE for Adobe on UTF-8")

new_re = ponyguruma.Regexp(".*Adobe.*")
if new_re.match(rawdata) != None:
   print("Ponyguruma RE matched! \t\t\t--- RE for Adobe on raw data")
else:
   print("Ponyguruma RE did not match\t\t\t--- RE for Adobe on raw data")
'''

我正在处理一个替代项目,并且在处理非 ASCII 编码文件时遇到了困难。这个问题是一个更大项目的一部分 - 最终我想用其他文本替换文本(我得到这个在 ASCII 中工作,但我无法识别其他编码中的出现。)再次感谢。

http://brian-stinar.blogspot.com

-布莱恩·J·斯蒂纳尔-

【问题讨论】:

  • 您的描述中完全缺少的东西是您的代码失败的方式。你在你的代码中写了“#这完全行不通”,但是你没有暗示它是如何行不通的。打印的字符串是空的吗?您是否收到错误消息/堆栈跟踪?

标签: python regex character-encoding


【解决方案1】:

您可能想要启用 DOTALL 标志,或者您想要使用 search 方法而不是 match 方法。即:

# DOTALL makes . match newlines 
re_UNSUB_amsterdam = re.compile(".*UNSUBSCRIBE.*", re.UNICODE | re.DOTALL)

或:

# search will find matches even if they aren't at the start of the string
... re_UNSUB_amsterdam.search(foo) ...

这些会给你不同的结果,但两者都应该给你匹配。 (看看你想要的类型。)

顺便说一句:您似乎混淆了编码文本(字节)和解码文本(字符)。这并不少见,尤其是在 3.x 之前的 Python 中。特别是,这是非常可疑的:

ISO_8859_2_encoded = rawdata.decode('ISO-8859-2')

您使用 ISO-8859-2 进行 de 编码,而不是 en 编码,因此将此变量称为“decoded”。 (为什么不是“ISO_8859_2_decoded”?因为 ISO_8859_2 是一种编码。解码后的字符串不再有编码。)

您的代码的其余部分正在尝试对 rawdata 和 UTF_8_encoded(两个编码字符串)进行匹配,而它可能应该使用解码后的 unicode 字符串。

【讨论】:

  • 非常感谢。添加 re.DOTALL 标志后,这完全符合我的预期。似乎 .* 在 ASCII 上的行为不同;在 ASCII 中,它与我匹配的换行符,但解码后的非 ASCII 不是,但我可能只是不清楚这一点。感谢您澄清编码文本和解码文本。这是我第一个处理不同编码的项目,感谢您的澄清。
【解决方案2】:

【讨论】:

    【解决方案3】:

    使用默认标志设置,.* 不匹配换行符。 UNSUBSCRIBE 只出现一次,在第一个换行符之后。 Adobe 出现在第一个换行符之前。你可以通过使用 re.DOTALL 来解决这个问题。

    但是您还没有检查您使用 Adob​​e 匹配得到的内容:它有 1478 字节宽!开启 re.DOTALL 并且它(以及相应的 UNSUBSCRIBE 模式)将匹配整个文本!

    您肯定需要输掉尾随的 .* - 您不感兴趣,这会减慢匹配速度。此外,您应该丢失前导 .* 并使用 search() 而不是 match()。

    在这种情况下,re.UNICODE 标志对您毫无用处——请阅读手册并了解它的作用。

    为什么要将数据转码为 UTF-8 并在其上进行搜索?只需保留 Unicode。

    其他人指出,一般来说,在对数据进行任何认真工作之前,您需要解码 Ӓ 等东西......但没有提到您的数据中包含的 « 等东西 :-)

    【讨论】:

      【解决方案4】:

      您的问题是关于正则表达式的,但是没有它们也可以解决您的问题;而是使用标准字符串replace 方法。

      import urllib
      raw = urllib.urlopen('http://www.cs.unm.edu/~brian.stinar/legal.html').read()
      decoded = raw.decode('iso-8859-2')
      type(decoded)    # decoded is now <type 'unicode'>
      substituted = decoded.replace(u'UNSUBSCRIBE', u'whatever you prefer')
      

      如果没有别的,上面显示了如何处理编码:只需解码为 un​​icode 字符串并使用它。但请注意,这仅适用于您只有一个或很少数量的替换(并且这些替换不是基于模式)的情况,因为replace() 一次只能处理一个替换。

      对于基于字符串和模式的替换,您可以执行以下操作来一次实现多个替换:

      import re
      REPLACEMENTS = ((u'[aA]dobe', u'!twiddle!'),
                      (u'UNS.*IBE', u'@wobble@'),
                      (u'Dublin', u'Sydney'))
      
      def replacer(m):
          return REPLACEMENTS[list(m.groups()).index(m.group(0))][1]
      
      r = re.compile('|'.join('(%s)' % t[0] for t in REPLACEMENTS))
      substituted = r.sub(replacer, decoded)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-21
        • 1970-01-01
        • 1970-01-01
        • 2016-04-22
        • 2018-03-16
        • 2017-01-23
        • 2017-01-25
        相关资源
        最近更新 更多