Java正则表达式在ascii范围之外不匹配,其行为与python正则表达式不同

Java正则表达式在ascii范围之外不匹配,其行为与python正则表达式不同,java,regex,scikit-learn,pattern-matching,countvectorizer,Java,Regex,Scikit Learn,Pattern Matching,Countvectorizer,我想用sklearn的方法过滤文档中的字符串。它使用以下正则表达式:(?u)\b\w\w+\b。 此java代码的行为方式应相同: Pattern regex = Pattern.compile("(?u)\\b\\w\\w+\\b"); Matcher matcher = regex.matcher("this is the document.!? äöa m²"); while(matcher.find()) { String match = matcher.group();

我想用sklearn的方法过滤文档中的字符串。它使用以下正则表达式:
(?u)\b\w\w+\b
。 此java代码的行为方式应相同:

Pattern regex = Pattern.compile("(?u)\\b\\w\\w+\\b");
Matcher matcher = regex.matcher("this is the document.!? äöa m²");

while(matcher.find()) {
    String match = matcher.group();
    System.out.println(match);
}
但这不会像python中那样产生所需的输出:

this
is
the
document
äöa
m²
它反而输出:

this
is
the
document

我该怎么做才能像python正则表达式那样包含非ascii字符呢?

还有一步要做:您需要指定
\w
也包含unicode字符<代码>模式。UNICODE\u字符\u类用于救援:

    Pattern regex = Pattern.compile("(?u)\\b\\w\\w+\\b", Pattern.UNICODE_CHARACTER_CLASS);
                                                   // ^^^^^^^^^^
    Matcher matcher = regex.matcher("this is the document.!? äöa m²");

    while(matcher.find()) {
        String match = matcher.group();
        System.out.println(match);
    }

正如Wiktor在评论中所建议的,您可以使用
(?U)
打开标志
UNICODE\U CHARACTER\U CLASS
。虽然这允许匹配
äöa
,但仍然不匹配
。这是因为带有
\w
UNICODE\u CHARACTER\u类
无法将
²
识别为有效的字母数字字符。作为
\w
的替代品,您可以使用
[\pN\pL\u]
。这与Unicode数字
\pN
和Unicode字母
\pL
(加上
\uu
)匹配。Unicode字符类包括
\pNo
字符类,其中包括拉丁语1增补-拉丁语1标点符号和符号字符类(包括
字符类)。或者,您可以将
\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的解释 查看,我们得到以下信息(我删除了与回答问题无关的信息):

Unicode支持 以下预定义字符类POSIX字符 等级符合附录C的建议: Unicode正则表达式的兼容性属性,当 指定了UNICODE字符类
标志

\w
一个单词字符:
[\p{Alpha}\p{gc=Mn}\p{gc=Me}\p{gc=Mc}\p{Digit}\p{gc=Pc}\p{IsJoin\u Control}]

太好了!现在,当使用
(?U)
标志时,我们有了
\w
的定义。将这些Unicode字符类插入将准确地告诉您每个Unicode字符类匹配的内容。在不把这篇文章写得太长的情况下,我将继续告诉您以下两个类都不匹配
²

  • \p{Alpha}
  • \p{gc=Mn}
  • \p{gc=Me}
  • \p{gc=Mc}
  • \p{Digit}
  • \p{gc=Pc}
  • \p{IsJoin\u Control}

Python的解释 那么,当
u
标志与
\w
一起使用时,为什么Python会匹配
u
?这一个很难找到,但我开始深入研究。在消除了许多关于如何调用此函数的漏洞之后,基本上会发生以下情况:

  • \w
    定义为
    CATEGORY\u UNI\u WORD
    ,然后在前面加上
    SRE
    SRE\u分类统一词
    calls
    SRE\u统一词(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_ISDIGIT(ch))
  • 这里重要的是
    Py\u UNICODE\u ISDECIMAL(ch)
    ,定义为
    Py\u UNICODE\u ISDECIMAL(ch)\u PyUnicode\u isdecimaldigital(ch)

现在,让我们看看方法>代码> 很好,因此基本上,如果字符的UTF-32编码字节具有

DECIMAL\u MASK
标志,这将计算为true,并返回大于或等于
0
的值


的UTF-32编码字节值是
0x000000b2
,我们的标志
十进制掩码是
0x02
0x000000b2&0x02
的计算结果为true,因此
在python中被视为有效的Unicode字母数字字符,因此
\w
u
标志匹配
²

Try
“(?u)\\b\\w\\w+\\b”
或仅匹配
”(?u)\\w{2,}”
@WiktorStribiżew对
äöa
有效,但对
m²无效
这可能有用吗?非常感谢。这适用于德语字母,但仍然不包括平方号(²),知道如何修复它吗?@LanceToth我使用的是Java,不是JavaScript
int _PyUnicode_IsDecimalDigit(Py_UCS4 ch)
{
    if (_PyUnicode_ToDecimalDigit(ch) < 0)
        return 0;
    return 1;
}
int _PyUnicode_ToDecimalDigit(Py_UCS4 ch)
{
    const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);

    return (ctype->flags & DECIMAL_MASK) ? ctype->decimal : -1;
}