Unicode-Entsprechungen für \ w und \ b in regulären Java-Ausdrücken?
Vielen modernen regex-Implementierungen interpretieren die \w
Charakter-Klasse Kürzel wie "beliebiger Buchstabe, eine Ziffer, oder eine Verbindung Interpunktion" (in der Regel: den Unterstrich). So ein regex wie \w+
entspricht Wörter wie hello
élève
GOÄ_432
oder gefräßig
.
Leider Java nicht. In Java \w
ist beschränkt auf [A-Za-z0-9_]
. Dies macht die passenden Wörter wie die oben genannten schwierig, neben anderen Problemen.
Es scheint auch, dass die \b
Trennzeichen entspricht in Orten, wo es nicht sollte.
Was wäre das korrekte äquivalent .NET-like, Unicode-aware \w
oder \b
in Java? Die anderen Abkürzungen müssen "umschreiben", um Sie Unicode-fähige?
InformationsquelleAutor der Frage Tim Pietzcker | 2010-11-29
Du musst angemeldet sein, um einen Kommentar abzugeben.
Quellcode
Den Quellcode für das umschreiben der Funktionen, die ich unten bespreche,ist hier verfügbar.
Update in Java 7
Sonne aktualisiert
Pattern
Klasse für JDK7 ist eine wunderbare neue fahne,UNICODE_CHARACTER_CLASS
der macht alles richtig funktioniert wieder. Es ist verfügbar als integrierbare(?U)
für den innen-Muster, so können Sie es verwenden, mit derString
Klasse Wrapper, zu. Er sports auch korrigiert Definitionen für verschiedene andere Eigenschaften, zu. Es verfolgt nun Den Unicode-Standard, in beiden RL1.2 und RL1.2a von UTS#18: Unicode, Reguläre Ausdrücke. Dies ist eine spannende und dramatische Verbesserung, und die Entwicklung der Mannschaft ist zu loben für diese wichtige Anstrengung.Java Regex Unicode-Probleme
Das problem mit Java regexes ist, dass die Perl 1.0 charclass entweicht — Bedeutung
\w
\b
\s
\d
und ergänzt — nicht in Java erweitertes arbeiten mit Unicode. Allein unter diesen\b
genießt bestimmte erweiterte Semantik, aber diese Karte weder\ - w
noch Unicode-Bezeichnernoch Unicode-line-break-Eigenschaften.Zusätzlich die POSIX-Eigenschaften in Java zugegriffen werden, auf diese Weise:
Dies ist ein echtes Chaos, weil es bedeutet, dass Dinge wie
Alpha
Lower
undSpace
tun nicht in Java-Karte, um die Unicode -Alphabetic
Lowercase
oderWhitespace
Eigenschaften. Dies ist exceeedingly ärgerlich. Java die Unicode-Unterstützung der Eigenschaft ist streng antemillennialvon denen ich meine, es unterstützt keine Unicode-Eigenschaft, die in den letzten zehn Jahren.Nicht in der Lage, darüber zu sprechen Leerzeichen korrekt ist super-ärgerlich. Betrachten wir die folgende Tabelle. Für jeden dieser code-Punkte, es gibt sowohl eine J-Spalte Ergebnisse
für Java-und eine P-Spalte Ergebnisse für Perl oder anderen PCRE-regex-basierte engine:
Sehen?
Praktisch jedem Java-white-space-Ergebnisse falsch nach Unicode. Es ist ein wirklich großes problem. Java ist einfach nur Durcheinander, Antworten zu geben, die sind "falsch" nach der bisherigen Praxis und auch nach Unicode. Plus Java gar nicht geben Ihnen Zugriff auf die echte Unicode-Eigenschaften! In der Tat, die Java nicht unterstützen alle Eigenschaft entspricht Unicode-Leerzeichen.
Die Lösung für Alle Diese Probleme und Mehr
Umgang mit diesem und vielen anderen Problemen, gestern schrieb ich eine Java-Funktion zum umschreiben einer musterzeichenfolge, schreibt diese 14 charclass entweicht:
indem Sie Sie mit Dingen, die tatsächlich arbeiten zu match Unicode in eine konsistente und vorhersagbare Weise. Es ist nur ein alpha-Prototyp von einem einzigen hack-session, aber es ist völlig funktionsfähig.
Die kurze Geschichte ist, dass mein code schreibt die 14 wie folgt:
Einige Dinge zu beachten...
Verwendet für seine
\X
definition, was Unicode bezieht sich jetzt auf als legacy grapheme clusternicht ein extended grapheme clusterda letztere eher komplizierter. Perl selbst verwendet nun die ausgefalleneren version, aber die alte version ist immer noch perfekt geeignet für die meisten gängigen Situationen. EDIT: Siehe Nachtrag unten.Was zu tun
\d
hängt davon ab, Ihre Absicht, aber der Standard ist die Uniode definition. Ich kann sehen, wie Menschen, die nicht immer wollen\p{Nd}
aber manchmal entweder[0-9]
oder\pN
.Den beiden Grenz-Definitionen
\b
und\B
ausdrücklich geschrieben, dass die\w
definition.Dass
\w
definition ist allzu breit, denn es packt die parenned Buchstaben nicht nur die eingekreisten lieben. Die Unicode -Other_Alphabetic
- Eigenschaft ist nicht verfügbar, bis JDK7, so dass die beste Sie tun können.Erkundung Der Grenzen
Grenzen kein problem gewesen, seit Larry Wall zunächst prägte den
\b
und\B
syntax für das Gespräch über diese für Perl 1.0 im Jahr 1987. Der Schlüssel zum Verständnis, wie\b
und\B
beide arbeiten zu zerstreuen, die zwei allgegenwärtigen Mythen über Sie:\w
Wort-Zeichen, nie für nicht-Wort-Zeichen.Einen
\b
Grenze bedeutet:Und die sind alle definiert ist vollkommen unkompliziert:
(?<=\w)
.(?=\w)
.(?<!\w)
.(?!\w)
.Deshalb, da
IF-THEN
ist kodiert als eineand
ed-zusammenAB
in regexes, einor
istX|Y
und weil dieand
ist höher im Rang alsor
das ist einfachAB|CD
. Also jeder\b
das bedeutet, dass eine Grenze kann sicher ersetzt mit:mit der
\w
definiert in der entsprechenden Weise.(Man könnte denken, es seltsam, dass die
A
undC
Komponenten sind Gegensätze. In einer perfekten Welt, sollten Sie in der Lage sein zu schreiben, dassAB|D
aber für eine Weile war ich der Jagd nach gegenseitigen Ausschluss Widersprüche in der Unicode-Eigenschaften, die ich denke ich habe aufgepasst, aber ich habe die doppelte Bedingung, die in der Grenze nur für den Fall. Und dies macht es mehr erweiterbar, wenn Sie weitere Ideen später.)Für die
\B
non-Grenzen, die Logik ist:Dass alle Instanzen von
\B
ersetzt werden mit:Diese wirklich ist, wie
\b
und\B
Verhalten. Entspricht Muster für Sie sind\b
mit der((IF)THEN|ELSE)
Konstrukt ist(?(?<=\w)(?!\w)|(?=\w))
\B
mit der((IF)THEN|ELSE)
Konstrukt ist(?(?=\w)(?<=\w)|(?<!\w))
Aber die Versionen mit nur
AB|CD
sind in Ordnung, vor allem, wenn Sie Mangel bedingte Muster in der regex-Sprache wie Java. ☹Hab ich schon überprüft das Verhalten der Grenzen mit der alle drei äquivalente Definitionen mit einem test-suite überprüft 110,385,408 Spiele pro run, und die ich ausgeführt habe über ein Dutzend verschiedene Daten Konfigurationen nach:
Jedoch, die Menschen wollen oft eine andere Art von Grenze. Sie wollen etwas, das whitespace-und edge-of-string bewusst:
(?:(?<=^)|(?<=\s))
(?=$|\s)
Befestigung Java mit Java
Den code, den ich gepostet in meine andere Antwort bietet diese und noch einige weitere Bequemlichkeiten. Diese enthält Definitionen für die Natürliche-Sprache-Wörter, Gedankenstriche, Bindestriche, Apostrophe, plus ein bisschen mehr.
Es ermöglicht Ihnen auch das festlegen von Unicode-Zeichen im logischen code-Punkte, nicht in idiotischen UTF-16 surrogates. Es ist schwer zu überbeanspruchung, wie wichtig das ist! Und das ist nur für die string-expansion.
Für regex charclass substitution, die macht der charclass in Ihre Java-regexes schließlich Arbeit auf Unicode und korrekt funktionieren, greifen die vollständige Quelle von hier. Sie kann mit ihm tun, wie du willst, natürlich. Wenn Sie die fixes, die ich lieben würde, zu hören, aber Sie nicht haben, um. Es ist ziemlich kurz. Die Eingeweide der wichtigsten regex-rewriting-Funktion ist einfach:
Sowieso, dass code ist nur ein alpha-release, Sachen, die ich gehackt über das Wochenende. Es wird nicht so bleiben.
Für die beta will ich:
Falten zusammen die code-Duplizierung
bieten eine klarere Schnittstelle hinsichtlich der unescaping string escapes versus augmentation regex entweicht
bieten eine gewisse Flexibilität bei der
\d
expansion, und vielleicht die\b
bieten bequeme Methoden, die Griff dreht er sich um und ruft Muster.kompilieren oder String.Spiele oder ähnliches für Sie
Für die Produktion freigeben haben sollte, javadoc und JUnit-test-suite. Ich kann meine gigatester, aber es ist nicht so geschrieben, wie Sie JUnit-tests.
Nachtrag
Ich habe gute Nachrichten und schlechte Nachrichten.
Die gute Nachricht ist, ich habe jetzt eine sehr nahe Annäherung an einen extended grapheme cluster für eine verbesserte
\X
.Die schlechte Nachricht ☺, ist, dass das Muster:
welche in Java würde man schreiben als:
¡Tschüß!
InformationsquelleAutor der Antwort tchrist
Es ist wirklich bedauerlich, dass
\w
funktioniert nicht. Die vorgeschlagene Lösung\p{Alpha}
bei mir nicht funktioniert entweder.Scheint es
[\p{L}]
fängt alle Unicode-Buchstaben. So ist die Unicode-Entsprechung der\w
sollte[\p{L}\p{Digit}_]
.InformationsquelleAutor der Antwort musiKk
In Java
\w
und\d
sind nicht Unicode-kompatibel ist; Sie nur die ASCII-Zeichen[A-Za-z0-9_]
und[0-9]
. Das gleiche gilt für\p{Alpha}
und Freunde (die POSIX "Charakter-Klassen" Sie sind auf sollen locale-sensitive, aber in Java Sie haben immer nur abgestimmt ASCII-Zeichen). Wenn Sie möchten, zu entsprechen Unicode "Wort-Zeichen", Sie haben zu buchstabieren Sie es aus, z.B.[\pL\p{Mn}\p{Nd}\p{Pc}]
,für Briefe, non-spacing Modifier (Akzente), Ziffern und die Verbindung von Satzzeichen.Jedoch, Java
\b
ist Unicode-fähigen; er verwendetCharacter.isLetterOrDigit(ch)
und prüft, für akzentuierte Buchstaben wie gut, aber die einzige "Verbindung Satzzeichen" - Zeichen erkennt, ist der Unterstrich. EDIT:wenn ich versuche dein Beispiel-code, druckt es""
undélève"
wie es sollte (sehen es auf ideone.com).InformationsquelleAutor der Antwort Alan Moore