Unicode-Äquivalente für \ w und \ b in regulären Java-Ausdrücken?

126

Viele moderne Regex-Implementierungen interpretieren die \wKurzform der Zeichenklasse als "einen beliebigen Buchstaben, eine Ziffer oder eine verbindende Interpunktion" (normalerweise: Unterstrich). Auf diese Weise, ein regulärer Ausdruck wie \w+Streichhölzer Wörter wie hello, élève, GOÄ_432oder gefräßig.

Java leider nicht. In Java \wist beschränkt auf [A-Za-z0-9_]. Dies macht es unter anderem schwierig, Wörter wie die oben genannten zu finden.

Es scheint auch, dass das \bWorttrennzeichen an Stellen übereinstimmt, an denen es nicht sollte.

Was wäre das richtige Äquivalent zu einem .NET-ähnlichen, Unicode-fähigen \woder \bin Java? Welche anderen Verknüpfungen müssen neu geschrieben werden, um Unicode-fähig zu machen?

Tim Pietzcker
quelle
3
Die Kurzgeschichte, Tim, ist, dass sie alle schreiben müssen, um sie mit Unicode in Einklang zu bringen. Ich sehe immer noch keine Anzeichen dafür, dass Java 1.7 mit Unicode-Eigenschaften mehr zu tun hat, als endlich Unterstützung für Skripte hinzuzufügen, aber das war's. Es gibt einige Dinge, die Sie wirklich nicht tun können, ohne besser auf alle Unicode-Eigenschaften zugreifen zu können. Wenn Sie meine Uniprops und Unichars- Skripte (und Uninames ) noch nicht haben , sind sie atemberaubende Augenöffner für all dies.
Tchrist
Man könnte erwägen, der Wortklasse Markierungen hinzuzufügen. Da zum Beispiel & auml; kann in Unicode entweder als \ u0061 \ u0308 oder \ u00E4 dargestellt werden.
Mostowski Zusammenbruch
3
Hey Tim, schau dir mein UPDATE an. Sie haben eine Flagge hinzugefügt, damit alles funktioniert. Hurra!
Tchrist

Antworten:

240

Quellcode

Der Quellcode für die unten beschriebenen Umschreibfunktionen ist hier verfügbar .

Update in Java 7

Die aktualisierte PatternKlasse von Sun für JDK7 hat eine wunderbare neue Flagge, UNICODE_CHARACTER_CLASSmit der alles wieder richtig funktioniert. Es ist als Einbettung (?U)für das Muster verfügbar , sodass Sie es auch mit den StringWrappern der Klasse verwenden können. Es enthält auch korrigierte Definitionen für verschiedene andere Eigenschaften. Es verfolgt jetzt den Unicode-Standard sowohl in RL1.2 als auch in RL1.2a aus UTS # 18: Unicode Regular Expressions . Dies ist eine aufregende und dramatische Verbesserung, und das Entwicklungsteam ist für diese wichtige Anstrengung zu loben.


Java Regex Unicode Probleme

Das Problem mit Java Regexes ist , dass die Perl 1.0 charclass entkommt - das heißt \w, \b, \s, \dund die Ergänzungen - sind in Java nicht mit Unicode Arbeit erweitert. Allein unter dieser \bgenießt bestimmte erweiterte Semantik, aber diese Karte weder zu \w, noch auf Unicode - Kennungen , noch auf Unicode Zeilenumbruch Eigenschaften .

Darüber hinaus wird auf die POSIX-Eigenschaften in Java folgendermaßen zugegriffen:

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}

Dies ist ein echtes Chaos, weil es bedeutet , dass Dinge wie Alpha, Lowerund Spacetun nicht in Java Karte , um die Unicode Alphabetic, Lowercaseoder WhitespaceEigenschaften. Das ist außerordentlich ärgerlich. Die Unterstützung von Java-Unicode-Eigenschaften ist streng antemillennial , womit ich meine, dass sie keine Unicode-Eigenschaft unterstützt, die im letzten Jahrzehnt herausgekommen ist.

Es ist sehr ärgerlich, nicht richtig über Leerzeichen sprechen zu können. Betrachten Sie die folgende Tabelle. Für jeden dieser Codepunkte gibt es sowohl eine J-Ergebnisspalte für Java als auch eine P-Ergebnisspalte für Perl oder eine andere PCRE-basierte Regex-Engine:

             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  -

Siehst du das?

Praktisch jedes dieser Java-Leerraumergebnisse ist laut Unicode ̲w̲r̲o̲n̲g̲. Es ist ein wirklich großes Problem. Java ist nur durcheinander und gibt Antworten, die gemäß der bestehenden Praxis und auch gemäß Unicode „falsch“ sind. Außerdem gibt Ihnen Java nicht einmal Zugriff auf die echten Unicode-Eigenschaften! Tatsächlich unterstützt Java keine Eigenschaft, die dem Unicode-Leerzeichen entspricht.


Die Lösung für all diese Probleme und mehr

Um dieses und viele andere verwandte Probleme zu lösen, habe ich gestern eine Java-Funktion geschrieben, um eine Musterzeichenfolge neu zu schreiben, die diese 14 Zeichenklassen-Escapezeichen neu schreibt:

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

indem Sie sie durch Dinge ersetzen, die tatsächlich so funktionieren, dass sie auf vorhersehbare und konsistente Weise mit Unicode übereinstimmen. Es ist nur ein Alpha-Prototyp aus einer einzelnen Hack-Sitzung, aber es ist voll funktionsfähig.

Die Kurzgeschichte ist, dass mein Code diese 14 wie folgt umschreibt:

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

Einige Dinge zu beachten ...

  • Dies verwendet für seine \XDefinition das, was Unicode jetzt als Legacy-Graphemcluster bezeichnet , nicht als erweiterten Graphemcluster , da letzterer etwas komplizierter ist. Perl selbst verwendet jetzt die schickere Version, aber die alte Version ist für die häufigsten Situationen immer noch perfekt funktionsfähig. BEARBEITEN: Siehe Anhang unten.

  • Was zu tun ist, \dhängt von Ihrer Absicht ab, aber die Standardeinstellung ist die Uniodendefinition. Ich kann Leute sehen, die nicht immer wollen \p{Nd}, aber manchmal entweder [0-9]oder \pN.

  • Die beiden Grenzdefinitionen \bund \Bsind speziell für die Verwendung der \wDefinition geschrieben.

  • Diese \wDefinition ist zu weit gefasst, weil sie die geschriebenen Buchstaben erfasst, nicht nur die eingekreisten. Die Unicode- Other_AlphabeticEigenschaft ist erst in JDK7 verfügbar. Das ist also das Beste, was Sie tun können.


Grenzen erkunden

Grenzen sind ein Problem, seit Larry Wall 1987 erstmals die Syntax \bund die \BSyntax für Perl 1.0 geprägt hat. Der Schlüssel zum Verständnis, wie \bund \Bbeide funktionieren, besteht darin, zwei allgegenwärtige Mythen über sie zu zerstreuen:

  1. Sie suchen immer nur für \wWortzeichen, nie für Nicht-Wort - Zeichen.
  2. Sie suchen nicht speziell nach der Kante der Zeichenfolge.

Eine \bGrenze bedeutet:

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

Und diese sind alle ganz einfach definiert als:

  • folgt Wort ist (?<=\w).
  • vorausgeht Wort ist (?=\w).
  • folgt nicht Wort ist (?<!\w).
  • nicht precede Wort ist (?!\w).

Da dies in Regexen IF-THENals and Ed- ABTogether codiert ist, ist ein oris X|Y, und weil das andeine höhere Priorität hat als or, ist das einfach AB|CD. Alles \b, was bedeutet, dass eine Grenze sicher ersetzt werden kann durch:

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

mit dem \win geeigneter Weise definierten.

(Man könnte denken , es seltsam , dass die Aund CKomponenten Gegensätze sind in einer perfekten Welt, sollten Sie in der Lage sein , das zu schreiben. AB|D, Aber für eine Weile war ich die Jagd nach mutual exclusion Widersprüchen in Unicode - Eigenschaften - was ich denke , ich habe gesorgt , aber ich habe die doppelte Bedingung für alle Fälle in der Grenze belassen. Außerdem ist sie erweiterbarer, wenn Sie später zusätzliche Ideen erhalten.)

Für \Bdie Nichtgrenzen lautet die Logik:

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

Zulassen, dass alle Instanzen von \Bersetzt werden durch:

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

Das ist wirklich wie \bund wie man sich \Bverhält. Äquivalente Muster für sie sind

  • \bmit dem ((IF)THEN|ELSE)Konstrukt ist(?(?<=\w)(?!\w)|(?=\w))
  • \Bmit dem ((IF)THEN|ELSE)Konstrukt ist(?(?=\w)(?<=\w)|(?<!\w))

Aber die Versionen mit just AB|CDsind in Ordnung, besonders wenn Sie keine bedingten Muster in Ihrer Regex-Sprache haben - wie Java. ☹

Ich habe das Verhalten der Grenzen bereits anhand aller drei äquivalenten Definitionen mit einer Testsuite überprüft, die 110.385.408 Übereinstimmungen pro Lauf überprüft und die ich auf einem Dutzend verschiedener Datenkonfigurationen ausgeführt habe:

     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)

Menschen wollen jedoch oft eine andere Art von Grenze. Sie wollen etwas, das Whitespace- und String-Edge-fähig ist:

  • linker Rand als(?:(?<=^)|(?<=\s))
  • rechter Rand als(?=$|\s)

Java mit Java reparieren

Der Code, den ich in meiner anderen Antwort gepostet habe, bietet dies und einige andere Annehmlichkeiten. Dies beinhaltet Definitionen für Wörter in natürlicher Sprache, Bindestriche, Bindestriche und Apostrophe sowie ein bisschen mehr.

Außerdem können Sie Unicode-Zeichen in logischen Codepunkten angeben, nicht in idiotischen UTF-16-Ersatzzeichen. Es ist schwer zu betonen, wie wichtig das ist! Und das ist nur für die String-Erweiterung.

Für regex charclass Substitution, die die charclass in Java macht Regexes schließlich Arbeit auf Unicode, und die Arbeit richtig, greifen hier die vollständige Quelle . Sie können natürlich damit machen, wie Sie möchten. Wenn Sie Korrekturen vornehmen, würde ich gerne davon hören, aber das müssen Sie nicht. Es ist ziemlich kurz. Der Mut der Hauptfunktion zum Umschreiben von Regex ist einfach:

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;

Wie auch immer, dieser Code ist nur eine Alpha-Veröffentlichung, Sachen, die ich über das Wochenende gehackt habe. Das wird nicht so bleiben.

Für die Beta habe ich vor:

  • Falten Sie die Codeduplizierung zusammen

  • Bieten Sie eine klarere Oberfläche für das Entweichen von Zeichenfolgen-Escapezeichen im Vergleich zu erweiterten Regex-Escapezeichen

  • bieten eine gewisse Flexibilität bei der \dErweiterung, und vielleicht die\b

  • Stellen Sie bequeme Methoden bereit, mit denen Sie sich umdrehen und Pattern.compile oder String.matches oder so weiter aufrufen können

Für die Produktionsversion sollte es über Javadoc und eine JUnit-Testsuite verfügen. Ich kann meinen Gigatester einschließen, aber er ist nicht als JUnit-Test geschrieben.


Nachtrag

Ich habe gute und schlechte Nachrichten.

Die gute Nachricht ist, dass ich jetzt eine sehr enge Annäherung an einen erweiterten Graphemcluster habe , um ihn für eine Verbesserung zu verwenden \X.

Die schlechte Nachricht ist, dass dieses Muster ist:

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

welche in Java würden Sie schreiben als:

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
quelle
10
Das ist großartig. Vielen Dank.
Tim Pietzcker
9
Christus, das ist eine erleuchtete Antwort. Ich bekomme nur nicht die Jon Skeet Referenz. Was hat er damit zu tun?
BalusC
12
@ BalusC: Es ist ein Hinweis auf Jon, der früher sagte, er würde mich die Frage stellen lassen. Aber bitte lassen Sie das nicht tin @tchrist fallen. Es könnte zu meinem Kopf gehen. :)
tchrist
3
Haben Sie darüber nachgedacht, dies dem OpenJDK hinzuzufügen?
Martijn Verburg
2
@ Martinijn: Ich hatte nicht, nein; Ich wusste nicht, dass es so „offen“ ist. :) Aber ich habe darüber nachgedacht, es in einem formaleren Sinne zu veröffentlichen; andere in meiner Abteilung möchten, dass dies erledigt wird (mit einer Art Open-Source-Lizenz, wahrscheinlich BSD oder ASL). Ich werde wahrscheinlich die API von dem in diesem Alpha-Prototyp ändern, den Code bereinigen usw. Aber es hilft uns enorm und wir gehen davon aus, dass es auch anderen helfen wird. Ich wünschte wirklich, Sun würde etwas gegen ihre Bibliothek unternehmen, aber Oracle schafft kein Vertrauen.
Tchrist
15

Es ist wirklich bedauerlich, dass \wdas nicht funktioniert. Die vorgeschlagene Lösung \p{Alpha}funktioniert auch bei mir nicht.

Es scheint [\p{L}]alle Unicode-Buchstaben zu fangen. Das Unicode-Äquivalent von \wsollte also sein [\p{L}\p{Digit}_].

musiKk
quelle
Stimmt aber \wauch mit Ziffern und mehr überein. Ich denke nur für Briefe, \p{L}würde funktionieren.
Tim Pietzcker
Du hast recht. \p{L}reicht. Ich dachte auch, dass nur Buchstaben das Problem sind. [\p{L}\p{Digit}_]sollte alle alphanumerischen Zeichen einschließlich Unterstrich abfangen.
musiKk
@MusicKk: In meiner Antwort finden Sie eine vollständige Lösung, mit der Sie Ihre Muster normal schreiben und dann eine Funktion durchlaufen können, die Javas klaffende Lücken korrigiert, damit sie unter Unicode ordnungsgemäß funktionieren.
Tchrist
Nein, \wwird von Unicode als viel breiter als nur \pLund die ASCII-Ziffern aller dummen Dinge definiert. Sie müssen schreiben, [\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]wenn Sie ein Unicode-fähiges möchten\w für Java - oder Sie können einfach meine unicode_charclassFunktion von hier aus verwenden . Es tut uns leid!
Tchrist
1
@ Tim, ja, denn Briefe \pLfunktionieren (Sie müssen keine Ein-Buchstaben-Requisiten annehmen ). Sie möchten dies jedoch selten, da Sie ziemlich vorsichtig sein müssen, dass Ihre Übereinstimmung keine unterschiedlichen Antworten erhält, nur weil Ihre Daten in Unicode-Normalisierungsform D (auch bekannt als NFD, was kanonische Zerlegung bedeutet ) vorliegen und nicht in NFC (NFD, gefolgt von kanonisch) Zusammensetzung ). Ein Beispiel ist, dass der Codepunkt U + E9 ( "é") \pLin NFC-Form vorliegt, seine NFD-Form jedoch zu U + 65.301 wird, also übereinstimmt \pL\pM. Sie können irgendwie umgehen dies mit \X: (?:(?=\pL)\X), aber Sie werden meine Version davon für Java benötigen. :(
tchrist
7

In Java \wund \dsind nicht Unicode-fähig; Sie stimmen nur mit den ASCII-Zeichen überein, [A-Za-z0-9_]und [0-9]. Das Gleiche gilt für \p{Alpha}und Freunde (die POSIX "Zeichenklassen", auf denen sie basieren, sollen länderspezifisch sein, aber in Java haben sie immer nur ASCII-Zeichen gefunden). Wenn Sie mit Unicode- "Wortzeichen" übereinstimmen möchten, müssen Sie diese buchstabieren, z. B. [\pL\p{Mn}\p{Nd}\p{Pc}]für Buchstaben, nicht räumliche Modifikatoren (Akzente), Dezimalstellen und Interpunktionszeichen.

Java \b ist jedoch Unicode-versiert. Es verwendet Character.isLetterOrDigit(ch)und sucht auch nach Buchstaben mit Akzent, aber das einzige Zeichen, das es erkennt, ist der Unterstrich. BEARBEITEN: Wenn ich Ihren Beispielcode ausprobiere, wird er gedruckt ""und élève"wie er sollte ( siehe ideone.com ).

Alan Moore
quelle
Es tut mir leid, Alan, aber Sie können wirklich nicht sagen, dass Java \bUnicode-versiert ist. Es macht Tonnen und Tonnen von Fehlern. "\u2163=", "\u24e7="Und "\u0301="alle angepassten Muster nicht "\\b="in Java, sondern sollte zu - wie perl -le 'print /\b=/ || 0 for "\x{2163}=", "\x{24e7}=", "\x{301}="'offenbart. Wenn Sie jedoch (und nur dann) meine Version einer Wortgrenze anstelle der nativen \bin Java austauschen, funktionieren diese auch in Java.
Tchrist
@tchrist: Ich habe die \bRichtigkeit nicht kommentiert und nur darauf hingewiesen, dass sie mit Unicode-Zeichen (wie in Java implementiert) funktioniert, nicht nur mit ASCII-ähnlichen \wund Freunden. Es funktioniert jedoch korrekt in Bezug darauf, \u0301wann dieses Zeichen mit einem Basiszeichen gepaart ist, wie in e\u0301=. Und ich bin nicht davon überzeugt, dass Java in diesem Fall falsch ist. Wie kann eine Kombinationsmarke als Wortzeichen betrachtet werden, wenn sie nicht Teil eines Graphemclusters mit einem Buchstaben ist?
Alan Moore
3
@Alan, dies wurde geklärt, als Unicode Graphemcluster durch Erörterung erweiterter und älterer Graphemcluster klarstellte. Die alte Definition eines Graphemclusters, in dem \Xfür eine Nichtmarke gefolgt von einer beliebigen Anzahl von Markierungen steht, ist problematisch, da Sie in der Lage sein sollten, alle Dateien als übereinstimmend zu beschreiben /^(\X*\R)*\R?$/, dies jedoch nicht, wenn Sie \pMzu Beginn eine haben die Datei oder sogar einer Zeile. Sie haben es also so erweitert, dass es immer mindestens einem Zeichen entspricht. Das hat es immer getan, aber jetzt funktioniert das obige Muster.[… Fortsetzung…]
tchrist
2
@ Alan, es schadet mehr als nützt, dass Java nativ ist \b teilweise Unicode- ist. Ziehen Sie in Betracht, die Zeichenfolge "élève"mit dem Muster abzugleichen \b(\w+)\b. Sehen Sie das Problem?
Tchrist
1
@tchrist: Ja, ohne die Wortgrenzen, \w+findet zwei Übereinstimmungen: lund ve, was schlimm genug ist. Aber mit den Wortgrenzen findet es nichts, weil es \berkennt éund èals Wortzeichen. Zumindest \bund \wsollte sich darüber einig sein, was ein Wortcharakter ist und was nicht.
Alan Moore