代码之家  ›  专栏  ›  技术社区  ›  Brian Stinar

Python Unicode正则表达式

  •  0
  • Brian Stinar  · 技术社区  · 15 年前

    我使用的是Python2.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·斯蒂纳-

    4 回复  |  直到 13 年前
        1
  •  2
  •   Laurence Gonsalves    15 年前

    您可能想要启用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编码,而不是 -编码,所以称这个变量为“decoded”。(为什么不“ISO_8859_2_decoded”?因为ISO_8859_2是一种编码。解码的字符串不再有编码。)

    代码的其余部分尝试在rawdata和UTF_8_编码(两种编码字符串)上进行匹配,而它可能应该使用解码的unicode字符串。

        3
  •  0
  •   John Machin Santi    15 年前

    对于默认标志设置,.*与换行符不匹配。“取消订阅”仅在第一行换行后出现一次。Adobe出现在第一个换行符之前。你可以通过使用re.DOTALL来解决这个问题。

    不过,您还没有检查Adobe match的性能:它有1478字节宽!打开re.DOTALL,它(以及相应的取消订阅模式)将匹配整个文本!!

    你肯定要输掉这场比赛,因为你不感兴趣,这会拖慢比赛。此外,还应丢失前导。*,并使用search()而不是match()。

    为什么要将数据转换成UTF-8并在上面搜索?就这样离开吧。

    还有人指出,一般来说,你需要解码 Ӓ 在对你的数据进行任何严肃的工作之前。。。但是没有提到 « 您的数据中添加的etc内容:-)

        4
  •  0
  •   mhawke    15 年前

    你的问题是关于正则表达式的,但是没有正则表达式你的问题是可以解决的;而是使用标准字符串 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')
    

    如果没有其他内容,上面展示了如何处理编码:只需解码为unicode字符串并使用它即可。但是请注意,这只适用于只有一个或很少数量的替换(这些替换不是基于模式的),因为 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)