如评论中Wiktor所建议的,您可以使用(?U)
来打开UNICODE_CHARACTER_CLASS
标志。虽然这确实允许匹配äöa
,但仍无法匹配m²
。这是因为带有\w
的UNICODE_CHARACTER_CLASS
不会将²
识别为有效的字母数字字符。作为对\w
的替代,您可以使用[\pN\pL_]
。这匹配Unicode数字\pN
和Unicode字母\pL
(加上_
)。\pN
Unicode字符类包括\pNo
字符类,它包括Latin 1 Supplement - Latin-1 punctuation and symbols字符类(其中包括²³¹
)。或者,您可以将\pNo
Unicode字符类添加到具有\w
的字符类中。这意味着以下正则表达式正确匹配您的字符串:
[\pN\pL_]{2,} # Matches any Unicode number or letter, and underscore
(?U)[\w\pNo]{2,} # Uses UNICODE_CHARACTER_CLASS so that \w matches Unicode.
# Adds \pNo to additionally match ²³¹
所以为什么在Java中
\w
不能匹配
²
,但在Python中可以呢?
Java的解释
查看OpenJDK 8-b132的Pattern
实现,我们可以得到以下信息(我删除了与回答问题无关的信息):
Unicode支持
以下预定义字符类和POSIX字符类符合Unicode正则表达式的兼容性属性附录C建议,当指定UNICODE_CHARACTER_CLASS
标志时。
\w
一个单词字符:[\p{Alpha}\p{gc=Mn}\p{gc=Me}\p{gc=Mc}\p{Digit}\p{gc=Pc}\p{IsJoin_Control}]
太好了!现在我们有一个定义,当使用(?U)
标志时,可以对\w
进行插入。将这些Unicode字符类插入this amazing tool中,将告诉您每个Unicode字符类精确匹配的内容。为了不让这篇文章变得太长,我只会告诉你以下两个类都不匹配²
:
\p{Alpha}
\p{gc=Mn}
\p{gc=Me}
\p{gc=Mc}
\p{Digit}
\p{gc=Pc}
\p{IsJoin_Control}
Python的解释
那么为什么在使用u
标志与\w
一起时,Python会匹配²³¹
?这个问题很难追踪,但我深入研究了Python的源代码(我使用的是Python 3.6.5rc1-2018-03-13)。在删除了很多关于如何调用它的琐碎内容后,基本上发生了以下情况:
\w
被定义为 CATEGORY_UNI_WORD
,然后加上前缀 SRE_
。 SRE_CATEGORY_UNI_WORD
调用 SRE_UNI_IS_WORD(ch)
SRE_UNI_IS_WORD
被定义为 (SRE_UNI_IS_ALNUM(ch) || (ch) == '_')
。
SRE_UNI_IS_ALNUM
调用 Py_UNICODE_ISALNUM
,它又被定义为 (Py_UNICODE_ISALPHA(ch) || Py_UNICODE_ISDECIMAL(ch) || Py_UNICODE_ISDIGIT(ch) || Py_UNICODE_ISNUMERIC(ch))
。
- 这里重要的是
Py_UNICODE_ISDECIMAL(ch)
,它被定义为 Py_UNICODE_ISDECIMAL(ch) _PyUnicode_IsDecimalDigit(ch)
。
现在,让我们来看一下方法 _PyUnicode_IsDecimalDigit(ch)
:
int _PyUnicode_IsDecimalDigit(Py_UCS4 ch)
{
if (_PyUnicode_ToDecimalDigit(ch) < 0)
return 0;
return 1;
}
正如我们所看到的,如果
_PyUnicode_ToDecimalDigit(ch) < 0
,这个方法会返回
1
。那么
_PyUnicode_ToDecimalDigit
是什么样子的呢?
int _PyUnicode_ToDecimalDigit(Py_UCS4 ch)
{
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
return (ctype->flags & DECIMAL_MASK) ? ctype->decimal : -1;
}
总之,如果字符的UTF-32编码字节具有 DECIMAL_MASK
标志,则表达式结果为true,将返回大于或等于 0
的值。
²
的UTF-32编码字节值为 0x000000b2
,我们的标志 DECIMAL_MASK
是 0x02
。 0x000000b2 & 0x02
结果为 true,因此在python中,\w
与 u
标志匹配 ²
被视为有效的Unicode字母数字字符。
"(?U)\\b\\w\\w+\\b"
或者仅使用"(?U)\\w{2,}"
。 - Wiktor Stribiżewäöa
可以工作,但针对m²
无法工作。 - ctwheels"(?U)[\\w\\p{No}]{2,}"
。 - Wiktor Stribiżew