2014-03-07 5 views
13

Ich habe eine Eingabezeichenfolge.Gleichen Sie eine Zeichenfolge mit mehreren Regex-Mustern

Ich denke darüber nach, wie diese Zeichenfolge mit mehr als einem regulären Ausdruck effektiv übereinstimmen.

Example Input: ABCD 

ich gegen diese reg-ex-Muster passen mag, und true zurück, wenn zumindest einer von ihnen übereinstimmt:

[a-zA-Z]{3} 

^[^\\d].* 

([\\w&&[^b]])* 

Ich bin nicht sicher, wie auf einmal gegen mehrere Muster entsprechen . Kann mir jemand sagen, wie wir es effektiv machen?

+2

Ihre Frage ist unklar (zumindest für mich). Was meinst du mit effektiv? Möchten Sie prüfen, ob die Eingabe allen Regexes entspricht oder nur eines ausreicht? Können Sie neben Input auch die erwartete Ausgabe angeben? – Pshemo

+1

Ich denke, dass Sie in erster Linie in natürlicher Sprache definieren sollten, welche Art von Char-Sequenzen Sie übereinstimmen möchten. Ihr Beispiel lässt uns kein Muster extrahieren. Oder, im besten Fall, hier ist ein Muster, das am besten zu Ihrer Eingabe passt: "ABCD". –

+0

Was möchten Sie erreichen? – wumpz

Antwort

19

Wenn Sie nur ein paar reguläre Ausdrücke haben, und sie sind alle bekannten zur Kompilierzeit, dann kann dies genug sein:

private static final Pattern 
    rx1 = Pattern.compile("..."), 
    rx2 = Pattern.compile("..."), 
    ...; 

return rx1.matcher(s).matches() || rx2.matcher(s).matches() || ...; 

Wenn es mehr von ihnen gibt, oder sie geladen sind zur Laufzeit, dann verwenden Sie eine Liste von Mustern:

final List<Pattern> rxs = new ArrayList<>(); 


for (Pattern rx : rxs) if (rx.matcher(input).matches()) return true; 
return false; 
+0

Ein komplettes Dokument hier: https://dzone.com/refcardz/regular-expressions – Benj

+5

Was ist der effektivste Weg: mehrere Matcher oder mehrere Muster durch Rohre verbunden? – Benj

1

Ich bin mir nicht sicher, was effectively Mittel, aber wenn es um Leistung und Sie wollen eine Menge von Zeichenketten überprüfen, die ich für dieses

gehen würde
... 
static Pattern p1 = Pattern.compile("[a-zA-Z]{3}"); 
static Pattern p2 = Pattern.compile("^[^\\d].*"); 
static Pattern p3 = Pattern.compile("([\\w&&[^b]])*"); 

public static boolean test(String s){ 
    return p1.matcher(s).matches ? true: 
     p2.matcher(s).matches ? true: 
     p3.matcher(s).matches; 
} 

Ich bin nicht sicher, wie es beeinflussen Leistung, aber die Kombination aller in einem Regexp mit | könnte auch helfen.

+0

Dies führt zu einer Neuerfindung von logischen oder fehlenden Klammern. Warum nicht 'p1.matcher (s) .matches() || verwenden p2.matcher (s) .matches() || p3.matcher (s) .matches() ' – kratenko

+0

Sie haben absolut Recht. Ich weiß nicht, was ich vor 4 Jahren gedacht habe. – NeplatnyUdaj

1

Um das erneute Erstellen von Instanzen von Pattern- und Matcher-Klassen zu vermeiden, können Sie jeweils eine davon erstellen und sie erneut verwenden. Um die Klasse Matcher wiederzuverwenden, können Sie die Methode reset(newInput) verwenden. Warnung: Dieser Ansatz ist nicht threadsicher. Verwenden Sie es nur, wenn Sie garantieren können, dass nur ein Thread diese Methode verwenden kann, andernfalls erstellen Sie für jeden Methodenaufruf eine separate Instanz von Matcher.

Dies ist eines der möglichen Codebeispiele

private static Matcher m1 = Pattern.compile("regex1").matcher(""); 
private static Matcher m2 = Pattern.compile("regex2").matcher(""); 
private static Matcher m3 = Pattern.compile("regex3").matcher(""); 

public boolean matchesAtLeastOneRegex(String input) { 
    return  m1.reset(input).matches() 
      || m2.reset(input).matches() 
      || m3.reset(input).matches(); 
} 
+1

Der ganze Zweck für die Existenz von "Matcher" besteht darin, es jedes Mal zu erstellen, um den Status einer einzelnen Übereinstimmungsaktion beizubehalten. Ihr Code ist nicht Thread-sicher. –

+0

@MarkoTopolnik Wahr. Danke, dass du darauf hingewiesen hast. In einer Thread-Umgebung scheint das Zurücksetzen von Matcher etwas schneller zu sein, als es neu zu erstellen. Daher habe ich beschlossen, es in meiner Antwort zu erwähnen. Hoffe, meine Bearbeitung macht meine Antwort besser. – Pshemo

18

Sie eine große regex aus den einzelnen diejenigen machen können:

[a-zA-Z]{3}|^[^\\d].*|([\\w&&[^b]])* 
+1

@MarkoTopolnik Danke für Korrekturen, war unsicher über den Vorrang der | also hatte ich es in Parens eingewickelt, um sicher zu sein – vandale

+2

Da die Parens auch Gruppenerfassung implizieren, sollten sie mit Vorsicht behandelt werden. –

+0

Aber gibt es dann eine Möglichkeit zu wissen, welcher meiner Regex tatsächlich zusammenpasst? Ich verstehe, dass es vielleicht nicht das Ziel von @ Patan ist, aber ich brauchte etwas Ähnliches. – Sap

0

Hier ist eine Alternative. Beachten Sie, dass dies in einer bestimmten Reihenfolge nicht zurückgegeben wird. Das könnte man aber tun, indem man zum Beispiel nach m.start() sortiert.

private static HashMap<String, String> regs = new HashMap<String, String>(); 

...

regs.put("COMMA", ","); 
    regs.put("ID", "[a-z][a-zA-Z0-9]*"); 
    regs.put("SEMI", ";"); 
    regs.put("GETS", ":="); 
    regs.put("DOT", "\\."); 

    for (HashMap.Entry<String, String> entry : regs.entrySet()) { 
     String key = entry.getKey(); 
     String value = entry.getValue(); 
     Matcher m = Pattern.compile(value).matcher("program var a, b, c; begin a := 0; end."); 
     boolean f = m.find(); 
     while(f) 
     { 
      System.out.println(key); 
      System.out.print(m.group() + " "); 
      System.out.print(m.start() + " "); 
      System.out.println(m.end()); 
      f = m.find(); 
     } 

    } 
} 
Verwandte Themen