Ekwiwalenty Unicode dla \ wi \ b w wyrażeniach regularnych Java?

126

Wiele nowoczesnych implementacji wyrażeń regularnych interpretuje \wskrót klasy znaków jako „dowolną literę, cyfrę lub łączącą interpunkcję” (zwykle: podkreślenie). W ten sposób regex podobne \w+dopasowania słów podoba hello, élève, GOÄ_432lub gefräßig.

Niestety Java nie. W Javie \wjest ograniczony do [A-Za-z0-9_]. Utrudnia to między innymi dopasowywanie słów, takich jak te wymienione powyżej.

Okazuje się również, że \bseparator słów pasuje tam, gdzie nie powinien.

Jaki byłby właściwy odpowiednik środowiska podobnego do .NET, obsługującego Unicode \wlub \bJava? Które inne skróty wymagają „przepisania”, aby obsługiwały Unicode?

Tim Pietzcker
źródło
3
Krótka historia, Tim, jest taka, że wszyscy muszą napisać, aby dostosować je do Unicode. Nadal nie widzę oznak, że Java 1.7 zrobi coś więcej z właściwościami Unicode niż w końcu dodanie obsługi skryptów, ale to wszystko. Jest kilka rzeczy, których naprawdę nie można zrobić bez lepszego dostępu do pełnego zestawu właściwości Unicode. Jeśli nie masz jeszcze moich unipropsów i skryptów unichars (i uninames ), są one oszałamiającymi otwierającymi oczy w tym wszystkim.
tchrist
Można by rozważyć dodanie znaków do słowa klasa. Ponieważ na przykład & auml; można przedstawić w Unicode jako \ u0061 \ u0308 lub \ u00E4.
Mostowski Collapse
3
Hej Tim, sprawdź moją AKTUALIZACJĘ. Dodali flagę, aby wszystko działało. Hurra!
tchrist

Odpowiedzi:

240

Kod źródłowy

Kod źródłowy funkcji przepisywania, które omówię poniżej, jest dostępny tutaj .

Aktualizacja w Javie 7

Zaktualizowana Patternklasa Sun dla JDK7 ma cudowną nową flagę UNICODE_CHARACTER_CLASS, która sprawia, że ​​wszystko znów działa poprawnie. Jest dostępny jako osadzalny element (?U)wewnątrz wzorca, więc można go również używać z Stringopakowaniami klasy. Zawiera również poprawione definicje różnych innych właściwości. Teraz śledzi standard Unicode, zarówno w RL1.2, jak i RL1.2a z UTS # 18: Wyrażenia regularne Unicode . To ekscytująca i radykalna poprawa, a zespół programistów zasługuje na pochwałę za ten ważny wysiłek.


Problemy z Regex Unicode w Javie

Problem z wyrażeniami regularnymi w Javie polega na tym, że klasa znaków Perl 1.0 ucieka - co oznacza \w,\b , \s, \di ich uzupełnienia - nie są w Javie przedłużony do pracy z Unicode. Tylko jeden z nich \bcieszy się pewną rozszerzoną semantyką, ale nie odwzorowują one ani na \w, ani na identyfikatory Unicode , ani na właściwości podziału wiersza Unicode .

Dodatkowo do właściwości POSIX w Javie można uzyskać dostęp w następujący sposób:

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}

To jest prawdziwy bałagan, bo to oznacza, że wszystko podoba Alpha, LoweriSpace zrobić nie w mapie Java dla Unicode Alphabetic, Lowercase, lub Whitespacewłaściwości. To jest wyjątkowo irytujące. Obsługa właściwości Unicode w Javie jest ściśle sprzed tysiąclecia , co oznacza, że ​​nie obsługuje żadnej właściwości Unicode, która pojawiła się w ciągu ostatniej dekady.

Brak możliwości prawidłowego mówienia o białych znakach jest bardzo irytujący. Rozważ poniższą tabelę. Dla każdego z tych punktów kodowych istnieje zarówno kolumna wyników w języku J dla języka Java, jak i kolumna wyników P dla języka Perl lub dowolnego innego silnika wyrażeń regularnych opartego na PCRE:

             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  -

Zobaczyć, że?

Praktycznie każdy z tych wyników białych znaków Java jest zgodny z Unicode ̲w̲r̲o̲n̲g̲. To jest naprawdę duży problem. Java jest po prostu pomieszana, dając odpowiedzi, które są „błędne” zgodnie z istniejącą praktyką, a także zgodnie z Unicode. Plus Java nawet nie daje Ci dostępu do prawdziwych właściwości Unicode! W rzeczywistości Java nie obsługuje żadnej właściwości, która odpowiada białym znakom Unicode.


Rozwiązanie wszystkich tych problemów i nie tylko

Aby poradzić sobie z tym i wieloma innymi powiązanymi problemami, wczoraj napisałem funkcję Java, aby przepisać ciąg wzorca, który przepisuje te 14 znaków ucieczki klas:

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

zastępując je rzeczami, które faktycznie działają, aby dopasować Unicode w przewidywalny i spójny sposób. To tylko prototyp alfa z jednej sesji hakerskiej, ale jest w pełni funkcjonalny.

Krótko mówiąc, mój kod przepisuje te 14 w następujący sposób:

\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*)

Kilka rzeczy do rozważenia ...

  • Który wykorzystuje do jej \Xdefinicji, co Unicode teraz odnosi się do postaci klastra spuścizna grafem , a nie rozszerzonym klastra grafem , jak ten ostatni jest raczej bardziej skomplikowana. Sam Perl używa teraz bardziej wyszukanej wersji, ale stara wersja jest nadal doskonale funkcjonalna w większości typowych sytuacji. EDYCJA: patrz dodatek na dole.

  • Co zrobić, \dzależy od Twoich zamiarów, ale domyślną definicją jest Uniode. Widzę, że ludzie nie zawsze chcą \p{Nd}, ale czasami albo [0-9]albo \pN.

  • Dwie definicje granic \bi \Bsą specjalnie napisane w celu użycia \wdefinicji.

  • \wDefinicja ta jest zbyt szeroka, ponieważ obejmuje nie tylko litery zapisane w spreferze. Właściwość Unicode Other_Alphabeticjest dostępna dopiero w JDK7, więc to najlepsze, co możesz zrobić.


Odkrywanie granic

Granice były problemem odkąd Larry Wall po raz pierwszy ukuł składnię \bi \Bdo mówienia o nich w Perlu 1.0 w 1987 roku. Klucz do zrozumienia, jak \bi\B obie działają, jest rozwianie dwóch wszechobecnych mitów na ich temat:

  1. tylko kiedykolwiek patrząc na \wznaki słowne, nigdy dla znaków non-słownych.
  2. Nie szukają specjalnie krawędzi sznurka.

A \bbrzegowe oznaczają:

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

A to wszystko jest zdefiniowane w prosty sposób jako:

  • podąża za słowem jest (?<=\w).
  • poprzedza słowo jest (?=\w).
  • nie wynika haseł IS(?<!\w) .
  • nie poprzedza słowa jest (?!\w).

Dlatego, skoro IF-THENjest kodowany jako and ed-together ABw wyrażeniach regularnych, to orjest X|Y, a ponieważ the andma wyższy priorytet niż or, to jest po prostu AB|CD. Więc każdy \b, co oznacza granicę można bezpiecznie zastąpić:

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

ze \wzdefiniowanym w odpowiedni sposób.

(Możesz pomyśleć, że to dziwne, że komponenty Ai Csą przeciwieństwami. W idealnym świecie powinieneś być w stanie to napisać AB|D, ale przez chwilę ścigałem wzajemne wykluczające się sprzeczności we właściwościach Unicode - co ja myślę, że się tym zająłem , ale na wszelki wypadek zostawiłem podwójny warunek w granicy. Dodatkowo, dzięki temu jest on bardziej rozszerzalny, jeśli później pojawią się dodatkowe pomysły.

W przypadku \Bbraku granic logika jest następująca:

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

Zezwalanie \Bna zastąpienie wszystkich wystąpień przez :

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

To naprawdę jest jak \bi \Bzachowuj się. Są dla nich równoważne wzory

  • \bużycie ((IF)THEN|ELSE)konstrukcji to(?(?<=\w)(?!\w)|(?=\w))
  • \Bużycie ((IF)THEN|ELSE)konstrukcji to(?(?=\w)(?<=\w)|(?<!\w))

Ale wersje z just AB|CD są w porządku, zwłaszcza jeśli brakuje wzorców warunkowych w Twoim języku regex - takim jak Java. ☹

Sprawdziłem już zachowanie granic przy użyciu wszystkich trzech równoważnych definicji za pomocą zestawu testów, który sprawdza 110 385 408 dopasowań na przebieg i który uruchomiłem na kilkunastu różnych konfiguracjach danych zgodnie z:

     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)

Jednak ludzie często chcą innego rodzaju granicy. Chcą czegoś, co jest świadome białych znaków i krawędzi łańcucha:

  • lewa krawędź jak(?:(?<=^)|(?<=\s))
  • prawa krawędź jak(?=$|\s)

Naprawianie Java za pomocą Java

Kod, który zamieściłem w mojej drugiej odpowiedzi zapewnia to i kilka innych udogodnień. Obejmuje to definicje słów, myślników, łączników i apostrofów w języku naturalnym, a także trochę więcej.

Pozwala także na określenie znaków Unicode w logicznych punktach kodowych, a nie w idiotycznych surogatach UTF-16. Trudno przecenić, jakie to ważne!A to tylko dla rozwinięcia ciągów.

Dla regex charclass podstawienie sprawia, że charclass w Javie regexes wreszcie pracę na Unicode, i działa prawidłowo, chwycić pełną źródło stąd . Możesz oczywiście zrobić z tym, co chcesz. Jeśli naprawisz to, chciałbym o tym usłyszeć, ale nie musisz. Jest dość krótki. Zalety głównej funkcji przepisywania wyrażeń regularnych są proste:

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;

W każdym razie ten kod to tylko wydanie alfa, coś, co zhakowałem w weekend. Tak nie zostanie.

W przypadku wersji beta zamierzam:

  • złóż razem powielenie kodu

  • zapewniają jaśniejszy interfejs dotyczący znaków ucieczki ciągów bez zmiany znaczenia w porównaniu ze znakami ucieczki wyrażenia rozszerzającego

  • zapewniają pewną elastyczność w \drozszerzaniu, a być może\b

  • zapewniają wygodne metody, które obsługują odwracanie i wywoływanie Pattern.compile lub String.matches lub co innego

W przypadku wydania produkcyjnego powinien mieć javadoc i zestaw testów JUnit. Mogę dołączyć mój gigatester, ale nie jest to napisane jako testy JUnit.


Uzupełnienie

Mam dobre i złe wieści.

Dobra wiadomość jest taka, że ​​mam teraz bardzo bliskie przybliżenie do rozszerzonego klastra grafemowego, którego można użyć do ulepszenia \X.

Zła wiadomość ☺ jest taka, że ​​ten wzór jest następujący:

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

które w Javie napiszesz jako:

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

¡Tschüß!

tchrist
źródło
10
To jest niesamowite. Wielkie dzięki.
Tim Pietzcker
9
Chryste, to oświecająca odpowiedź. Nie rozumiem tylko referencji Jona Skeeta. Co on ma z tym wspólnego?
BalusC
12
@BalusC: To odniesienie do Jona, który wcześniej powiedział, że pozwolił mi odpowiedzieć na to pytanie. Ale proszę, nie upuszczaj t@tchrist. To może uderzyć mi do głowy. :)
tchrist
3
Czy myślałeś o dodaniu tego do OpenJDK?
Martijn Verburg
2
@Martijn: Nie, nie; Nie wiedziałem, że to „otwarte”. :) Ale myślałem o wydaniu go w bardziej formalnym sensie; inni w moim dziale chcą, aby to się stało (z jakąś licencją typu open source, prawdopodobnie BSD lub ASL). Prawdopodobnie zamierzam zmienić API z tego, co jest w tym prototypie alfa, wyczyścić kod itp. Ale to nam bardzo pomaga i myślimy, że pomoże też innym. Naprawdę chciałbym, żeby Sun zrobił coś z ich biblioteką, ale Oracle nie budzi zaufania.
tchrist
15

To naprawdę niefortunne, że \wnie działa. Proponowane rozwiązanie\p{Alpha} też u mnie nie działa.

Wygląda na to, że [\p{L}]łapie wszystkie litery Unicode. Więc odpowiednikiem Unicode \wpowinno być [\p{L}\p{Digit}_].

musiKk
źródło
Ale \wpasuje także do cyfr i nie tylko. Myślę, że dla samych listów \p{L}będzie działać.
Tim Pietzcker
Masz rację. \p{L}wystarczy. Pomyślałem też, że problemem są tylko litery. [\p{L}\p{Digit}_]powinien przechwytywać wszystkie znaki alfanumeryczne, w tym podkreślenie.
muzyka muzyczna
@MusicKk: Zobacz moją odpowiedź, aby uzyskać kompletne rozwiązanie, które pozwala normalnie pisać wzorce, a następnie przekazać je przez funkcję, która koryguje luki z lukami w Javie, aby działała poprawnie w Unicode.
tchrist
Nie, \wjest definiowany przez Unicode jako znacznie szerszy niż tylko \pLi cyfry ASCII, ze wszystkich głupich rzeczy. Musisz napisać, [\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]jeśli chcesz mieć obsługę Unicode \wdla Java - lub możesz po prostu użyć mojej unicode_charclassfunkcji tutaj . Przepraszam!
tchrist
1
@Tim, tak, ponieważ litery \pLdziałają (nie musisz obejmować rekwizytów jednoliterowych). Jednak rzadko tego chcesz, ponieważ musisz być raczej ostrożny, aby twoje dopasowanie nie dawało różnych odpowiedzi tylko dlatego, że twoje dane są w formacie normalizacji Unicode D (aka NFD, co oznacza rozkład kanoniczny ), a nie będąc w NFC (NFD, po którym następuje kanoniczny skład ). Przykładem jest to, że punkt kodowy U + E9 ( "é") jest \pLw formie NFC, ale jego forma NFD staje się U + 65.301, więc pasuje \pL\pM. Można trochę obejść ten problem z \X: (?:(?=\pL)\X), ale trzeba moją wersję, że dla Javy. :(
tchrist
7

W Javie \w i \dnie obsługują Unicode; pasują tylko do znaków ASCII [A-Za-z0-9_]i [0-9]. To samo dotyczy \p{Alpha}i przyjaciół ("klasy znaków" POSIX, na których są oparte, mają być wrażliwe na ustawienia regionalne, ale w Javie zawsze dopasowywały tylko znaki ASCII). Jeśli chcesz dopasować „znaki słowne” Unicode, musisz je przeliterować, np. [\pL\p{Mn}\p{Nd}\p{Pc}]Dla liter, modyfikatorów bez odstępów (akcentów), cyfr dziesiętnych i łączących znaków interpunkcyjnych.

Jednak Java \b jest Unicode zrozumiały; używa Character.isLetterOrDigit(ch)i sprawdza również litery akcentowane, ale jedynym znakiem „łączącej interpunkcji”, który rozpoznaje, jest podkreślenie. EDYCJA: kiedy próbuję Twój przykładowy kod, drukuje ""i élève"tak, jak powinien ( zobacz na ideone.com ).

Alan Moore
źródło
Przykro mi, Alan, ale naprawdę nie możesz powiedzieć, że Java \bobsługuje Unicode. Robi mnóstwo błędów. "\u2163=", "\u24e7="i "\u0301="wszystkie nie pasują do wzorca "\\b="w Javie, ale powinny - jak perl -le 'print /\b=/ || 0 for "\x{2163}=", "\x{24e7}=", "\x{301}="'ujawnia. Jednakże, jeśli (i tylko wtedy) zamienisz w mojej wersji granicę słów zamiast natywnej \bw Javie, to wszystko będzie działać również w Javie.
tchrist
@tchrist: Nie komentowałem \bpoprawności, po prostu wskazałem , że działa na znakach Unicode (zaimplementowanych w Javie), a nie tylko na ASCII \wi znajomych. Jednak działa poprawnie w odniesieniu do \u0301sytuacji, gdy ta postać jest sparowana z postacią podstawową, jak w e\u0301=. I nie jestem przekonany, że w tym przypadku Java jest błędna. Jak łączący się znak można uznać za znak słowny, jeśli nie jest częścią klastra grafemów z literą?
Alan Moore
3
@Alan, to jest coś, co zostało wyjaśnione, gdy Unicode wyjaśnił klastry grafemów, omawiając rozszerzone i starsze klastry grafemowe. Stara definicja klastra grafemowego, w której \Xoznacza brak znaku, po którym następuje dowolna liczba znaków, jest problematyczna, ponieważ powinieneś być w stanie opisać wszystkie pliki jako pasujące /^(\X*\R)*\R?$/, ale nie możesz, jeśli masz \pMna początku plik, a nawet wiersz. Więc rozszerzyli go, aby zawsze pasował do co najmniej jednego znaku. Zawsze tak było, ale teraz sprawia, że ​​powyższy wzór działa. […
Ciąg
2
@Alan, bardziej szkodzi niż pożytku, że język Java \bjest częściowo zgodny z Unicode. Rozważ dopasowanie ciągu "élève"do wzorca \b(\w+)\b. Widzisz problem?
tchrist
1
@tchrist: Tak, bez granic słów \w+znajduje dwa dopasowania: li ve, co jest wystarczająco złe. Ale w przypadku granic słów nie znajduje nic, ponieważ \brozpoznaje éi èjako znaki słowne. Jako minimum \bi \wpowinien uzgodnić, co jest znakiem słowa, a co nie.
Alan Moore