【问题标题】:Regex [A-Z] Do Not Recognize Local Characters正则表达式 [A-Z] 不识别本地字符
【发布时间】:2018-10-22 11:54:09
【问题描述】:

我检查了其他问题并阅读了他们的解决方案,但它们不起作用。我已经测试了它适用于非语言环境字符的正则表达式。代码只是在字符串中找到任何大写字母并对其进行一些处理。例如minikŞeker bir kedi 将返回kŞe 但是我的代码无法将Ş 识别为[A-Z] 中的字母。当我按照某些人的要求尝试re.LOCALE 时,当我使用re.UNICODE 时出现错误ValueError: cannot use LOCALE flag with a str pattern

import re
corp = "minikŞeker bir kedi"
pattern = re.compile(r"([\w]{1})()([A-Z]{1})", re.U)
corp = re.sub(pattern, r"\1 \3", corp)
print(corp)

适用于minikSeker bir kedi 不适用于minikŞeker bir kedi,并为re.L 引发错误。我得到的错误是 ValueError: cannot use LOCALE flag with a str pattern 搜索它产生了一些 git 讨论,但没有任何用处。

【问题讨论】:

  • 我在正文的正文中添加了错误。我以前读过这个问题。 \u 逃脱没有奏效。与该链接的问题持有者不同,我对语言环境字符根本不感兴趣,我希望能够通过将它们包含在我的 [A-Z] 字符集中来执行我通常执行的任务
  • 据我了解,您希望输入“minikSeker bir kedi”(不带特殊字符)输出“kSe”,对吗?但它不起作用。
  • 我希望能够使用“minikŞeker kedi”并获得输出“minikŞeker kedi”。由于 [AZ] 无法识别 Ş 除非我构建像 [A-ZŞÇĞİÜ] 这样的模式,否则我无法识别,但是每次遇到 UTF-8 问题时都这样做是荒谬的,应该有一种方法可以将正则表达式指向UTF-8 字符集。
  • 您通常不想“将正则表达式指向 UTF-8 字符集”,您只想为您的模式和您的模式使用 Unicode str(或 unicode,对于 Python 2)搜索字符串,然后你就可以访问所有的 Unicode。事实上,如果您使用的是 Python 3,那么您已经在这样做了。但这并不能单独解决您的问题。

标签: python regex nlp


【解决方案1】:

abarnet 的回答很棒,但如果您只想查找大写字符,str.isupper() 无需额外模块即可工作。

>>> foo = "minikŞeker bir kedi"
>>> for i, c in enumerate(foo):
...     if c.isupper():
...         print(foo[i-1:i+2])
...         break
... 
kŞe

或许

>>> foo = "minikŞeker bir kedi"
>>> ''.join((' ' if c.isupper() else '') + c for c in foo)
'minik Şeker bir kedi'

【讨论】:

    【解决方案2】:

    问题是Ş 不在[A-Z] 范围内。该范围是其代码点位于 U+0040 和 U+005A(包括)的所有字符的类别。 (如果您使用字节模式,它将是 0x40 和 0x5A 之间的所有字节。)并且Ş 是 U+0153(或者,例如,0xAA 以字节为单位,假设 latin2)。不在那个范围内。

    使用语言环境不会改变这一点。正如re.LOCALE 解释的那样,它所做的只是:

    根据当前语言环境进行 \w、\W、\b、\B 和不区分大小写的匹配。

    此外,您几乎从不想使用re.LOCALE。正如文档所说:

    不鼓励使用此标志,因为语言环境机制非常不可靠,它一次只能处理一种“文化”,并且仅适用于 8 位语言环境。

    如果您只关心单个脚本,您可以为该脚本构建一个适当范围的类。

    如果您想使用 all 脚本,您需要使用 Unicode 字符类构建一个类,例如 Lu 用于“所有大写字母”。不幸的是,Python 的re 没有直接执行此操作的机制。你可以利用unicodedata 中的信息构建一个巨大的类,但这很烦人:

    Lu = '[' + ''.join(chr(c) for c in range(0, 0x10ffff) 
                       if unicodedata.category(chr(c)) == 'Lu') + ']'
    

    然后:

    pattern = re.compile(r"([\w]{1})()(" + Lu + r"{1})", re.U)
    

    ……或者也许:

    pattern = re.compile(rf"([\w]{{1}})()({Lu}{{1}})", re.U)
    

    但好消息是re 无法指定 Unicode 类的部分原因是长期以来,计划是用新模块替换re,所以很多人建议新re 的功能被拒绝。但好消息是,预期的新模块可作为第三方库使用,regex。它工作得很好,几乎可以替代re;它只是改进得太快,无法将其锁定到较慢的 Python 发布时间表。如果你安装它,那么你可以这样写你的代码:

    import regex
    corp = "minikŞeker bir kedi"
    pattern = regex.compile(r"([\w]{1})()(\p{Lu}{1})", re.U)
    corp = regex.sub(pattern, r"\1 \3", corp)
    print(corp)
    

    我所做的唯一更改是将re 替换为regex,然后使用\p{Lu} 而不是[A-Z]

    当然,还有许多其他正则表达式引擎,其中许多还支持 Unicode 字符类。大多数确实遵循相同\p 语法的一些变化。 (他们都是从 Perl 抄来的,但细节不同——例如,regex 的 Unicode 类想法来自 unicodedata 模块,而 PCREPCRE2 试图尽可能接近 Perl,等等。)

    【讨论】:

    • 非常感谢!这解决了我所有的问题!我可能在我未来的项目中经常使用正则表达式,因此这一次解决了很多未来的问题,我对添加模块并不陌生,我 conda 它,阅读文档并立即开始!
    猜你喜欢
    • 2011-04-01
    • 2011-06-22
    • 1970-01-01
    • 2011-10-04
    • 2011-08-26
    • 2011-05-13
    • 1970-01-01
    • 2012-08-05
    • 2010-12-11
    相关资源
    最近更新 更多