2013-05-29 17 views
21

Sagen wir, ich habe folgende Zeichenfolge:Wie über regulären Ausdruck iterieren

name1=gil;name2=orit; 

ich alle Spiele von name=value finden wollen und stellen Sie sicher, dass die gesamte Zeichenfolge mit dem Muster übereinstimmt.

Also habe ich folgendes:

  1. Stellen Sie sicher, dass das gesamte Muster übereinstimmt, was ich will.

    Pattern p = Pattern.compile("^((\\w+)=(\\w+);)*$"); 
    Matcher m = p.matcher(line); 
    if (!m.matches()) { 
        return false; 
    } 
    
  2. Iterate über das Muster name=value

    Pattern p = Pattern.compile("(\\w+)=(\\w+);"); 
    Matcher m = p.matcher(line); 
    while (m.find()) { 
        map.put(m.group(1), m.group(2)); 
    } 
    

Gibt es eine Möglichkeit, dies mit einer Regex zu tun?

Antwort

27

können Sie validieren und iterieren Spiele mit einem Regex von:

  • Gewährleistung gibt es keine unerreichten Zeichen zwischen den Spielen (zB name1=x;;name2=y;) durch einen Putting \G zu Beginn unserer Regex, die "the end of the previous match" bedeuten.

  • Überprüfen, ob das Ende der Zeichenfolge bei unserer letzten Übereinstimmung erreicht wurde, indem die Länge unserer Zeichenfolge mit Matcher.end() verglichen wird, die den Offset nach dem letzten übereinstimmenden Zeichen zurückgibt.

Etwas wie:

String line = "name1=gil;name2=orit;"; 
Pattern p = Pattern.compile("\\G(\\w+)=(\\w+);"); 
Matcher m = p.matcher(line); 
int lastMatchPos = 0; 
while (m.find()) { 
    System.out.println(m.group(1)); 
    System.out.println(m.group(2)); 
    lastMatchPos = m.end(); 
} 
if (lastMatchPos != line.length()) 
    System.out.println("Invalid string!"); 

Live demo.


Einige Sprachen könnten Sie ermöglichen, die einzelnen iterieren direkt Spiele von
^((\\w+)=(\\w+);)*$, aber ich glaube nicht, dass Sie dies in Java tun.

2

Sie müssen Multiline-Modus aktivieren, damit "^" und "$" wie erwartet funktionieren.

Pattern p = Pattern.compile("^(?:(\\w+)=(\\w+);)*$", Pattern.MULTILINE); 
while (m.find()) { 
    for (int i = 0; i < m.groupCount() - 2; i += 2) { 
     map.put(m.group(i + 1), m.group(i + 2)); 
    } 
} 

Kommentare, wo rechts, haben Sie immer durch passende Gruppen für jede Zeile zu durchlaufen sind und die äußere Gruppe (?:...) eine Nicht-Erfassung Gruppe zu machen.

+0

standardmäßig regex engine passt im mehrzeiligen Modus.did wollten Sie die Option dotall verwenden!. Auch in dem Beispiel in Frage, funktioniert Ihre Regex nicht .. – Anirudha

+0

@Anirudh: Nein, MULTILINE-Modus ist standardmäßig in Java nicht aktiviert . DOTALL Option wird hier nutzlos sein. – nhahtdh

+0

-1, da dies die Frage nicht beantwortet. – nhahtdh

0
String example = "name1=gil;name2=orit;"; 
Pattern pattern = Pattern.compile("((name[0-9]+?=(.+?);))+?"); 
Matcher matcher = pattern.matcher(example); 
// verifies full match 
if (matcher.matches()) { 
    System.out.println("Whole String matched: " + matcher.group()); 
    // resets matcher 
    matcher.reset(); 
    // iterates over found 
    while (matcher.find()) { 
     System.out.println("\tFound: " + matcher.group(2)); 
     System.out.println("\t--> name is: " + matcher.group(3)); 
    } 
} 

Ausgang:

Whole String matched: name1=gil;name2=orit; 
    Found: name1=gil; 
    --> name is: gil 
    Found: name2=orit; 
    --> name is: orit 
+1

Dies ist wirklich 1 Regex, aber es erfordert 2 Durchgänge über die Eingabe-Zeichenfolge (einmal in 'Übereinstimmungen()' und einmal in der Schleife mit 'find()') – nhahtdh

+0

@nhahtdh Sie haben Recht. Aber mir war hier keine "1-Pass-Grenze" bekannt. – Mena

+1

Nicht wirklich eine Einschränkung, nur um zu sagen, dass es sich nicht viel von der aktuellen Lösung von OP in Bezug auf die Anzahl der Durchgänge unterscheidet. – nhahtdh