2016-04-17 19 views
3

der Code:Java Regex Quantifiers in String Split

String s = "a12ij"; 

System.out.println(Arrays.toString(s.split("\\d?"))); 

Der Ausgang ist [a, i, j], die mich verwirrt. Wenn der Ausdruck gierig ist, sollte er nicht so viel wie möglich versuchen und sich dabei auf jede Ziffer aufteilen? Ich würde annehmen, dass die Ausgabe stattdessen [a,, i, j] sein sollte. Woher kommt dieser extra leere Charakter?

+1

Ja, '?' Ist gierig, aber nur bis zu 1 Zeichen. Das passiert also zweimal und du brauchst 2. Das ist ziemlich standardisiert. – Obicere

+0

@Obicere, die Verwendung von zwei "?" Würde so oft wie möglich mit der Übereinstimmung zwischen null und einmal gleichsetzen. –

+0

Was willst du * das Ausgabe-Array? – Bohemian

Antwort

3

Das Muster, das Sie nur mit sind Spiele eine Ziffer eine Zeit:

\d match a digit [0-9] 
? matches between zero and one time (greedy) 

Da Sie mehr als eine Ziffer haben sie einzeln auf beide aufgeteilt los ist. Sie können ganz einfach mehr als ein paar verschiedene Möglichkeiten, zu einem Zeitpunkt mehr als eine Ziffer entsprechen, sind hier ein paar:

\d match a digit [0-9] 
+? matches between one and unlimited times (lazy) 

Oder Sie könnten nur tun:

\d match a digit [0-9] 
+ matches between one and unlimited times (greedy) 

Welche wahrscheinlich wäre es, die am nächsten was ich denke, dass Sie wollen, obwohl es unklar ist.

Erläuterung:

Seit dem Token \d wird mit dem ? quantifier die Regex-Engine Ihre Split-Funktion sagt eine Ziffer zwischen Null und Eins Zeit anzupassen. Das muss alle Ihre Zeichen (Null) sowie jede übereinstimmende Ziffer (einmal) enthalten.

Youbild kann es so etwas wie diese:

a,1,2,i,j // each character represents (zero) and is split 
     | | 
    a, , ,i,j // digit 1 and 2 are each matched (once) 

Digit 1 und 2 wurden aufeinander abgestimmt, aber nicht gefangen - so sind sie geworfen, bleibt jedoch das Komma noch von der Split und ist nicht grundsätzlich entfernt zwei leere Saiten erzeugen.


Wenn Sie speziell gesuchten Ihr Ergebnis haben, wie a, ,i,j dann werde ich Ihnen einen Tipp geben. Sie wollen ( erfassen die \d igits als eine Gruppe zwischen einem und unbegrenzte Male +) gefolgt von der gierigen Qualifier ?. Ich empfehle Ihnen, eine der beliebten Regex-Seiten zu besuchen, auf der Sie mit Mustern und Quantifizierern experimentieren können. Es ist auch eine gute Art zu lernen und kann Ihnen viel beibringen!

The solution can be found here

+0

Ich bin nicht davon überzeugt, dass dies wirklich die Frage beantwortet. Ausgehend von dem, was das OP erwartete, glaube ich, dass er bereits wusste, dass es sich bei jeder Ziffer einzeln aufspaltete, aber die extra leere Zeichenfolge in der Ausgabe nicht verstand. – ajb

+0

@ajb: Das zweite Beispiel meiner Antwort sollte die "erwartete" Ausgabe erzeugen. Ich bin mir nicht sicher, warum irgendjemand eine leere Zeichenfolge in ihrem Array hätte, aber vielleicht gibt es einen guten Grund. –

+0

@ I'L'I Antwort für extra leere Zeichenfolgen ist wahrscheinlich hier http://StackOverflow.com/Questions/18870699/java-string-Split-Sometimes-Giving-blank-strings – 11thdimension

2

Die javadoc für split() ist nicht klar, was passiert, wenn ein Muster, das die leere Zeichenkette übereinstimmen kann. Meine beste Vermutung ist hier die Trennzeichen gefunden split() sind, was durch aufeinander folgende find() Aufrufe einer Matcher gefunden werden würde. Die javadoc für find() sagt:

Dieses Verfahren beginnt am Anfang dieser Region des Matcher, oder, wenn ein vorherigen Aufruf der Methode erfolgreich war und die Matcher hat nicht da zurückgesetzt wurde, wird beim ersten Zeichen nicht abgestimmt auf das vorherige Spiel .So

, wenn die Zeichenfolge "a12ij" ist und das Muster entspricht entweder eine einzelne Ziffer oder einen leeren String, dann sollte find() finden Sie Folgendes:

  • Leerer String beginnend bei der Position 0 (vor a)
  • Der String "1"
  • Der String "2"
  • Leere Zeichenkette beginnend an Position 3 (vor 012.). Dies liegt daran, dass "das erste Zeichen, das nicht zum vorherigen Spiel passt" das i ist.
  • Leere Zeichenfolge ab Position 4 (vor j).
  • Leere Zeichenfolge ab Position 5 (am Ende der Zeichenfolge).

Also, wenn die Matches sind der Teil durch die x bezeichnet, wobei ein x unter einem leeren, das Spiel bedeutet, ist eine leere Zeichenfolge:

a 1 2 i j 
x  x x x x x 

Nun, wenn wir an dem Teil aussehen zwischen die x 's, sie sind "a", "", "", "i", "j" wie Sie sehen. (Die Teilzeichenfolge vor der ersten leeren Zeichenfolge wird nicht zurückgegeben, da die split() javadoc sagt: "Eine Null-Breite-Übereinstimmung am Anfang erzeugt jedoch niemals eine solche leere führende Teilzeichenfolge." [Beachten Sie, dass dies ein neues Verhalten mit Java 8 sein kann.] split() gibt keine leeren Trailing-Teilstrings zurück.)

Ich müsste den Code für split() betrachten, um dieses Verhalten zu bestätigen. Aber es macht Sinn, das Javadoc Matcher zu betrachten, und es stimmt mit dem Verhalten überein, das Sie sehen.

MEHR: Ich habe von der Quelle bestätigt, dass split() auf Matcher und find() angewiesen ist, mit Ausnahme einer Optimierung für den gemeinsamen Fall der Aufspaltung auf ein Trennzeichen ein bekanntes Zeichen. So erklärt sich das Verhalten.

+0

können Sie bitte das gleiche mit der '1234' Eingabe mit der gleichen Regex' \\ d? 'Zu erklären. Da ich ein leeres Array [] erhalte, schlägt Ihre Antwort vor, dass es "[,,,,]' ist. – 11thdimension

+0

@ 11thdimension Ich frage mich, ob sie dies für Java 8 umgeschrieben haben? Ich habe eine Quelle online gefunden, aber es scheint Java 6 zu sein. Es gibt einen Ausdruck im Java 8 Javadoc, der nicht in Java 7 Javadoc ist, und der Code, den ich gefunden habe, wird dieser neuen Anforderung nicht folgen. Also musste offensichtlich etwas getan werden. Ich sollte die Quelle irgendwo haben, also werde ich versuchen, einen Blick darauf zu werfen. – ajb

+0

OK, es sieht so aus, als hätten sie ein wenig Logik hinzugefügt, um die anfängliche leere Zeichenkette zu unterdrücken, aber anders als das, und außer einer Optimierung, falls wir uns auf ein einfaches Zeichen aufteilen, sollte es dasselbe sein. Ich bekomme die gleiche Ausgabe wie du, aber ich verstehe es nicht. – ajb