栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Java正则表达式中 w和 b的Unicode等效项?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java正则表达式中 w和 b的Unicode等效项?

源代码

我下面讨论的重写功能的源代码可在此处获得。

Java 7中的更新

Sun的

PatternJDK7
更新类有一个很棒的新标志
UNICODE_CHARACTER_CLASS
,它使一切重新正常运行。它可以作为(?U)模式内部的可嵌入对象使用,因此你也可以将其与String类的包装器一起使用。它还针对其他各种属性修改了定义。现在跟踪
Unipre
标准,在这两个RL1.2和RL1.2a从UTS#18:Unipre的正则表达式。这是一个令人兴奋的巨大进步,开发团队的这一重要努力值得称赞。

Java的Regex Unipre问题

使用Java正则表达式的问题是,Perl的1.0 charclass将逃逸-这意味着

w
b
s
d
和它们的补-不是Java扩展工作使用
Unipre
。其中
b
只有一个具有某些扩展的语义,但是它们既不映射
w
Unipre
标识符,也不映射到
Unipre
换行属性。

此外,以这种方式访问​​Java中的POSIX属性:

POSIX syntax    Java syntax[[:Lower:]]     p{Lower}[[:Upper:]]     p{Upper}[[:ASCII:]]     p{ASCII}[[:Alpha:]]     p{Alpha}[[:Digit:]]     p{Digit}[[:Alnum:]]     p{Alnum}[[:Punct:]]     p{Punct}[[:Graph:]]     p{Graph}[[:Print:]]     p{Print}[[:Blank:]]     p{Blank}[[:Cntrl:]]     p{Cntrl}[[:XDigit:]]    p{XDigit}[[:Space:]]     p{Space}

这是一个真正的混乱,因为这意味着一些事情,如

Alpha
Lower
Space
做的不是在
Java
中映射为
Unipre Alphabetic
Lowercase
Whitespace
性质。这真是令人讨厌。Java的
Unipre
属性严格地是
antemillennial
,这意味着我不支持过去十年来出现的
Unipre
属性。

无法正确谈论空白是一件令人讨厌的事情。请考虑下表。对于每个代码点,Java都有一个J结果列,Perl或任何其他基于PCRE的正则表达式引擎都有一个P结果列:

  Regex    001A    0085    00A0    2029J  P    J  P    J  P    J  P     s    1  1    0  1    0  1    0  1    pZ    0  0    0  0    1  1    1  1 p{Zs}    0  0    0  0    1  1    0  0         p{Space}    1  1    0  1    0  1    0  1         p{Blank}    0  0    0  0    0  1    0  0    p{Whitespace}    -  1    -  1    -  1    -  1p{javaWhitespace}    1  -    0  -    0  -    1  - p{javaSpaceChar}    0  -    0  -    1  -    1  -

看到那个吗?

实际上,根据Unipre,这些Java空格结果中的每一个都是“ ̲”。这是一个很大的问题。 Java只是一团糟,根据现有惯例以及根据Unipre,给出的答案都是“错误的”。另外,Java甚至都不允许你访问真正的Unipre属性!实际上,Java不支持与Unipre空格相对应的任何属性。

所有这些问题的解决方案,以及更多

为了解决这个问题以及其他许多相关问题,昨天我编写了一个Java函数来重写模式字符串,该模式字符串重写了这14个charclass转义:

w W s S v V h H d D b B X R

通过以一种可预测且一致的方式将其替换为与Unipre匹配的实际工作来代替它们。它只是单个hack会话中的一个alpha原型,但功能完全正常。

简而言之,我的代码如下重写了这14个代码:

s => [u0009-u000Du0020u0085u00A0u1680u180Eu2000-u200Au2028u2029u202Fu205Fu3000]S => [^u0009-u000Du0020u0085u00A0u1680u180Eu2000-u200Au2028u2029u202Fu205Fu3000]v => [u000A-u000Du0085u2028u2029]V => [^u000A-u000Du0085u2028u2029]h => [u0009u0020u00A0u1680u180Eu2000-u200Au202Fu205Fu3000]H => [^u0009u0020u00A0u1680u180Eu2000u2001-u200Au202Fu205Fu3000]w => [pLpMp{Nd}p{Nl}p{Pc}[p{InEnclosedAlphanumerics}&&p{So}]]W => [^pLpMp{Nd}p{Nl}p{Pc}[p{InEnclosedAlphanumerics}&&p{So}]]b => (?:(?<=[pLpMp{Nd}p{Nl}p{Pc}[p{InEnclosedAlphanumerics}&&p{So}]])(?![pLpMp{Nd}p{Nl}p{Pc}[p{InEnclosedAlphanumerics}&&p{So}]])|(?<![pLpMp{Nd}p{Nl}p{Pc}[p{InEnclosedAlphanumerics}&&p{So}]])(?=[pLpMp{Nd}p{Nl}p{Pc}[p{InEnclosedAlphanumerics}&&p{So}]]))B => (?:(?<=[pLpMp{Nd}p{Nl}p{Pc}[p{InEnclosedAlphanumerics}&&p{So}]])(?=[pLpMp{Nd}p{Nl}p{Pc}[p{InEnclosedAlphanumerics}&&p{So}]])|(?<![pLpMp{Nd}p{Nl}p{Pc}[p{InEnclosedAlphanumerics}&&p{So}]])(?![pLpMp{Nd}p{Nl}p{Pc}[p{InEnclosedAlphanumerics}&&p{So}]]))d => p{Nd}D => P{Nd}R => (?:(?>u000Du000A)|[u000Au000Bu000Cu000Du0085u2028u2029])X => (?>PMpM*)

一些要考虑的事情…

  • X
    定义使用了Unipre现在称为传统字素簇而不是扩展字素簇的定义,因为后者更为复杂。Perl本身现在使用的是高级版本,但是对于大多数常见情况,旧版本仍然可以完美使用。编辑:请参阅底部的附录。
  • 该做什么
    d
    取决于你的意图,但默认值为Uniode定义。我看到人们并不总是想要
    p{Nd}
    ,但有时
    [0-9]
    还是想要
    pN
  • 专门编写了两个边界定义
    b
    B
    ,以使用该
    w
    定义。
  • w
    定义过于宽泛,因为它抓住了赦免字母,而不仅仅是带圆圈的字母。
    Unipre Other_Alphabetic
    属性直到JDK7才可用,所以这是你可以做的最好的事情。

探索边界

边界已自从拉里·沃尔首先创造了一个问题

b
B
语法在1987年谈论他们对Perl 1.0后面的关键是了解如何
b
B
这两个工作是打消她们两分无孔不入的神话:

  1. 他们永远只能找了
    w
    字的字符,从来没有对非单词字符。
  2. 他们没有专门寻找字符串的边缘。

一个

b
边界的机构:

    IF does follow word        THEN doesn't precede word    ELSIF doesn't follow word        THEN does precede word

所有这些都直接定义为:

  • 跟随单词
    is (?<=w)
  • 单词是之前
    (?=w)
  • 没有遵循单词
    is (?<!w)
  • 之前没有字的
    (?!w)

因此,由于IF-THEN被编码为and ED-一起AB在正则表达式,一个or是X|Y,并且因为and是在优先级高于or,即简单地AB|CD。因此,所有b这意味着可以用以下方法安全地替换边界:

    (?:(?<=w)(?!w)|(?<!w)(?=w))

w
适当的方式定义。

(你可能会觉得A和C组件是对立的,这很奇怪。在一个完美的世界中,你应该能够编写该代码AB|D,但是有一段时间我一直在追踪Unipre属性中的互斥矛盾-我认为我已经注意了,但我把双重条件留在了边界,以防万一。另外,如果以后有更多的想法,它也可以扩展。

对于

B
非边界,逻辑为:

    IF does follow word        THEN does precede word    ELSIF doesn't follow word        THEN doesn't precede word

允许将的所有实例

B
替换为:

    (?:(?<=w)(?=w)|(?<!w)(?!w))

这确实是怎样

b
B
行为方式。它们的等效模式是

  • b
    使用的
    ((IF)THEN|ELSE)
    构造是
    (?(?<=w)(?!w)|(?=w))
  • B
    使用的
    ((IF)THEN|ELSE)
    构造是
    (?(?=w)(?<=w)|(?<!w))

但是只要使用版本就AB|CD可以了,特别是如果你的正则表达式语言(例如Java)缺少条件模式时。

我已经使用测试套件检查了所有三个等效定义,验证了边界的行为,该套件每次运行检查110,385,408个匹配项,并且根据以下十个不同的数据配置运行了该测试套件:

     0 ..     7F    the ASCII range    80 ..     FF    the non-ASCII Latin1 range   100 ..   FFFF    the non-Latin1 BMP (Basic Multilingual Plane) range 10000 .. 10FFFF    the non-BMP portion of Unipre (the "astral" planes)

但是,人们通常希望使用另一种边界。他们想要一些空格和字符串边缘感知的东西:

  • 左边缘 为
    (?:(?<=^)|(?<=s))
  • 右边缘为
    (?=$|s)

    |
    用Java修复Java

我在其他答案中发布的代码提供了此功能,并提供了许多其他便利。其中包括自然语言单词,破折号,连字符和撇号的定义,以及更多定义。

它还允许你在逻辑代码点中指定Unipre字符,而不是在惯用的UTF-16替代中指定。很难强调这有多重要!那只是为了字符串扩展。

要进行正则表达式charclass替换,使Java regexes中的charclass 最终可以在Unipre上正常工作,请从此处 获取完整的源代码。 当然,你可以随便使用它。如果你对此进行了修复,我很想听听它,但你不必这样做。很短 正则表达式的主要重写功能很简单:

switch (pre_point) {    case 'b':  newstr.append(boundary);    break;     case 'B':  newstr.append(not_boundary);    break;     case 'd':  newstr.append(digits_charclass);    break;     case 'D':  newstr.append(not_digits_charclass);    break;     case 'h':  newstr.append(horizontal_whitespace_charclass);    break;     case 'H':  newstr.append(not_horizontal_whitespace_charclass);    break;     case 'v':  newstr.append(vertical_whitespace_charclass);    break;     case 'V':  newstr.append(not_vertical_whitespace_charclass);    break;     case 'R':  newstr.append(linebreak);    break;     case 's':  newstr.append(whitespace_charclass);    break;     case 'S':  newstr.append(not_whitespace_charclass);    break;     case 'w':  newstr.append(identifier_charclass);    break;     case 'W':  newstr.append(not_identifier_charclass);    break;     case 'X':  newstr.append(legacy_grapheme_cluster);    break;     default:   newstr.append('\');    newstr.append(Character.toChars(pre_point));    break; }saw_backslash = false;

无论如何,这些代码只是一个alpha版本,这是我在周末破解的内容。不会那样的。

对于Beta版,我打算:

  • 将代码重复折叠在一起
  • 提供关于转义字符串转义与增加正则表达式转义的更清晰的界面
  • d
    扩展提供了一些灵活性,也许
    b
  • 提供方便的方法来处理转身并为你调用Pattern.compile或String.matches或诸如此类的东西

对于生产版本,它应该具有javadoc和一个JUnit测试套件。我可能包括我的gigatester,但它不是JUnit测试编写的。

附录

我有好消息,也有坏消息。

好消息是,我现在已经非常接近扩展的字素簇,可以用来进行改进X。

坏消息☺是这种模式是:

(?:(?:u000Du000A)|(?:[u0E40u0E41u0E42u0E43u0E44u0EC0u0EC1u0EC2u0EC3u0EC4uAAB5uAAB6uAAB9uAABBuAABC]*(?:[u1100-u115FuA960-uA97C]+|([u1100-u115FuA960-uA97C]*((?:[[u1160-u11A2uD7B0-uD7C6][uAC00uAC1CuAC38]][u1160-u11A2uD7B0-uD7C6]*|[uAC01uAC02uAC03uAC04])[u11A8-u11F9uD7CB-uD7FB]*))|[u11A8-u11F9uD7CB-uD7FB]+|[^[p{Zl}p{Zp}p{Cc}p{Cf}&&[^u000Du000Au200Cu200D]]u000Du000A])[[p{Mn}p{Me}u200Cu200Du0488u0489u20DDu20DEu20DFu20E0u20E2u20E3u20E4uA670uA671uA672uFF9EuFF9F][p{Mc}u0E30u0E32u0E33u0E45u0EB0u0EB2u0EB3]]*)|(?s:.))

在Java中,你将其编写为:

String extended_grapheme_cluster = "(?:(?:\u000D\u000A)|(?:[\u0E40\u0E41\u0E42\u0E43\u0E44\u0EC0\u0EC1\u0EC2\u0EC3\u0EC4\uAAB5\uAAB6\uAAB9\uAABB\uAABC]*(?:[\u1100-\u115F\uA960-\uA97C]+|([\u1100-\u115F\uA960-\uA97C]*((?:[[\u1160-\u11A2\uD7B0-\uD7C6][\uAC00\uAC1C\uAC38]][\u1160-\u11A2\uD7B0-\uD7C6]*|[\uAC01\uAC02\uAC03\uAC04])[\u11A8-\u11F9\uD7CB-\uD7FB]*))|[\u11A8-\u11F9\uD7CB-\uD7FB]+|[^[\p{Zl}\p{Zp}\p{Cc}\p{Cf}&&[^\u000D\u000A\u200C\u200D]]\u000D\u000A])[[\p{Mn}\p{Me}\u200C\u200D\u0488\u0489\u20DD\u20DE\u20DF\u20E0\u20E2\u20E3\u20E4\uA670\uA671\uA672\uFF9E\uFF9F][\p{Mc}\u0E30\u0E32\u0E33\u0E45\u0EB0\u0EB2\u0EB3]]*)|(?s:.))";


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/431862.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号