首页 > 解决方案 > 正则表达式 [AZ] 不识别本地字符

问题描述

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

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 patternSearching for it 产生了一些 git 讨论,但没有任何用处。

标签: pythonregexnlp

解决方案


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

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

使 \w、\W、\b、\B 和不区分大小写的匹配取决于当前的语言环境。

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

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

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

如果要使用所有脚本,则需要从 Unicode 字符类中构建一个类,例如Lu“所有大写字母”。不幸的是,Pythonre没有直接执行此操作的机制。您可以根据 中的信息构建一个巨大的类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)

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

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


推荐阅读