亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java正則表達式中\w和\b的Unicode等價物?

Java正則表達式中\w和\b的Unicode等價物?

嗶嗶one 2019-06-25 17:03:04
Java正則表達式中\w和\b的Unicode等價物?許多現代regex實現解釋了\w字符類速記為“任何字母、數字或連接標點符號”(通常為:下劃線)。那樣的話,就像\w+匹配像這樣的單詞hello, élève, GO?_432或gefr??ig.不幸的是,Java沒有。在Java中,\w僅限于[A-Za-z0-9_]..這使得像上面提到的匹配詞很難匹配,還有其他的問題。似乎\b單詞分隔符在不應該匹配的地方匹配。什么才是與.NET類似的、Unicode感知的正確的等價物?\w或\b在爪哇?還有哪些快捷鍵需要“重寫”才能讓他們知道Unicode?
查看完整描述

3 回答

?
侃侃無極

TA貢獻2051條經驗 獲得超10個贊

源代碼

下面討論的重寫函數的源代碼在這里可以買到.

Java 7中的更新

太陽更新Pattern類有一個出色的新標志,UNICODE_CHARACTER_CLASS使一切恢復正常。它可以作為可嵌入的(?U)用于模式內部,因此您可以將其與String班上的包裝紙也是。它還修正了其他各種屬性的定義。它現在跟蹤Unicode標準,在這兩個RL1.2RL1.2a從…UTS#18:Unicode正則表達式..這是一個令人興奮和戲劇性的改進,開發團隊的這一重要工作值得贊揚。


Java的Regex Unicode問題

Java regexes的問題是Perl1.0字符類轉義-意思是\w\b\s\d它們的補充-不是在Java中擴展到與Unicode一起工作的。獨自一人在這些,\b享有一定的擴展語義,但這些映射都不是\w,也不去Unicode標識符,也不去Unicode換行屬性.

此外,以這種方式訪問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}

這真是一團糟,因為這意味著AlphaLower,和Space在Java映射到UnicodeAlphabeticLowercase,或Whitespace財產。這太煩人了。Java的Unicode屬性支持是嚴格每隔一年,我的意思是它不支持在過去十年中出現的Unicode屬性。

不能正確地談論空格是非常煩人的??紤]下表。對于這些代碼點中的每一個,都有用于Java的J-結果列和用于Perl的P-結果列,或者任何其他基于PCRE的regex引擎:

             Regex    001A    0085    00A0    2029
                      J  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    -  1\p{javaWhitespace}    1  -    0  -    0  -    1  -
 \p{javaSpaceChar}    0  -    0  -    1  -    1  -

看到了嗎?

Unicode稱,幾乎所有這些JAVA空白結果都是?w?r?o?n?g?。是個很大的問題。Java只是搞砸了,根據現有的實踐和Unicode給出的答案都是“錯誤的”。另外,Java甚至不允許您訪問真正的Unicode屬性!實際上,Java不支持任何屬性,該屬性對應于Unicode空白。


解決所有這些問題,還有更多

為了解決這個問題和許多其他相關問題,昨天我編寫了一個Java函數來重寫一個模式字符串,該字符串重寫了這14個charclass轉義:

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

將它們替換為能夠以可預測和一致的方式匹配Unicode的東西。它只是來自一個黑客會話的alpha原型,但它是完全功能的。

簡而言之,我的代碼重寫了這14條代碼,如下所示:

\s => [\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]\S => [^\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]\v => [\u000A-\u000D\u0085\u2028\u2029]\V => [^\u000A-\u000D\u0085\u2028\u2029]\h => [\u0009\u0020\u00A0\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]\H => [^\u0009\u0020\u00A0\u1680\u180E\u2000\u2001-\u200A\u202F\u205F\u3000]\w => [\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]\W => [^\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]\b => (?:(?<=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])|(?<![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]))\B => (?:(?<=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])|(?<![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]))\d => \p{Nd}\D => \P{Nd}\R => (?:(?>\u000D\u000A)|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029])\X => (?>\PM\pM*)

有些事情要考慮.。

  • 用于\X定義什么Unicode現在指的是作為遺留字形聚類,而不是擴展字形簇,因為后者更復雜。Perl本身現在使用更高級的版本,但在最常見的情況下,舊版本仍然是完全可行的。編輯:見下文增編。

  • 該怎么辦\d取決于您的意圖,但默認的是Uniode定義。我可以看到人們并不總是想要\p{Nd},但有時[0-9]\pN.

  • 兩個邊界定義,\b\B,則是專門編寫的,以便使用\w定義。

  • 那,那個\w定義過于寬泛,因為它抓住了括號內的字母,而不僅僅是圓圈字母。UnicodeOther_Alphabetic屬性在JDK 7之前是不可用的,所以這是您所能做的最好的。


探索邊界

自從拉里·沃爾(LarryWall)第一次發明\b\B1987年為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

這些都被完全直接地定義為:

  • 跟隨詞

    (?<=\w).

  • 先于文字

    (?=\w).

  • 不聽我的話

    (?<!\w).

  • 不先于單詞

    (?!\w).

因此,既然IF-THEN被編碼為and埃德-一起AB在雷克斯,orX|Y,因為and的優先級高于or,那是很簡單的AB|CD..所以每一個\b這意味著邊界可以安全地替換為:

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

帶著\w以適當的方式定義。

(你可能覺得奇怪的是AC組件是對立的。在一個完美的世界里,你應該能夠寫出AB|D,但有一段時間我一直在追尋Unicode屬性中的互斥矛盾-我我已經處理好了,但為了以防萬一,我把雙重條件留在了邊界上。另外,如果以后有額外的想法,這將使它更易于擴展。)

\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 Unicode (the "astral" planes)

然而,人們往往想要一種不同的界限。他們想要的是空格和字符串邊緣感知的東西:

  • 左緣

    (?:(?<=^)|(?<=\s))

  • 右緣

    (?=$|\s)


用Java修復Java

我發布的代碼我的另一個答案提供了這個和相當多的其他便利。這包括對自然語言單詞、破折號、連字符和撇號的定義,再加上更多。

它還允許您在邏輯代碼點中指定Unicode字符,而不是在愚蠢的UTF-16代名詞中指定。很難過分強調這是多么重要!這只是為了字符串的膨脹。

對于regex charclass替換,使您的Java regexes中的charclass最后做Unicode的工作,正確地工作,抓取來自這里的全部資料.當然,你可以隨心所欲地處理它。如果你修好了,我很想聽,但你不必這么做。很短。主regex重寫函數的核心很簡單:

switch (code_point) {

    case 'b':  newstr.append(boundary);
               break; /* switch */
    case 'B':  newstr.append(not_boundary);
               break; /* switch */

    case 'd':  newstr.append(digits_charclass);
               break; /* switch */
    case 'D':  newstr.append(not_digits_charclass);
               break; /* switch */

    case 'h':  newstr.append(horizontal_whitespace_charclass);
               break; /* switch */
    case 'H':  newstr.append(not_horizontal_whitespace_charclass);
               break; /* switch */

    case 'v':  newstr.append(vertical_whitespace_charclass);
               break; /* switch */
    case 'V':  newstr.append(not_vertical_whitespace_charclass);
               break; /* switch */

    case 'R':  newstr.append(linebreak);
               break; /* switch */

    case 's':  newstr.append(whitespace_charclass);
               break; /* switch */
    case 'S':  newstr.append(not_whitespace_charclass);
               break; /* switch */

    case 'w':  newstr.append(identifier_charclass);
               break; /* switch */
    case 'W':  newstr.append(not_identifier_charclass);
               break; /* switch */

    case 'X':  newstr.append(legacy_grapheme_cluster);
               break; /* switch */

    default:   newstr.append('\\');
               newstr.append(Character.toChars(code_point));
               break; /* switch */}saw_backslash = false;

不管怎么說,這段代碼只是一個alpha版本,是我周末黑的東西。不會一直這樣。

關于測試版,我打算:

  • 將代碼復制折疊在一起

  • 提供關于未轉義字符串轉義與增強regex轉義的更清晰的接口。

  • \d擴張,也許\b

  • 為您提供方便的方法來處理轉身和調用Pattern.L.6或String.Match或諸如此類的事情

對于生產版本,它應該有javadoc和一個JUnit測試套件。我可能包括我的gigatester,但它不是作為JUnit測試編寫的。


增編

我有好消息和壞消息。

好消息是我現在非常近似值擴展字形簇用于改進\X.

壞消息是?的模式是:

(?:(?:\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:.))

在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:.))";


查看完整回答
反對 回復 2019-06-25
?
四季花海

TA貢獻1811條經驗 獲得超5個贊

很不幸\w不管用。提議的解決方案\p{Alpha}對我也不管用。

似乎[\p{L}]捕獲所有Unicode字母。所以Unicode等效的\w應該是[\p{L}\p{Digit}_].


查看完整回答
反對 回復 2019-06-25
  • 3 回答
  • 0 關注
  • 1615 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號