web-dev-qa-db-fra.com

Faire correspondre une chaîne avec plusieurs motifs de regex

J'ai une chaîne d'entrée.

Je pense comment faire correspondre cette chaîne à plus d'une expression régulière de manière efficace.

Example Input: ABCD

J'aimerais faire correspondre ces modèles de rég-ex et renvoyer true si au moins l'un d'eux correspond:

[a-zA-Z]{3}

^[^\\d].*

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

Je ne suis pas sûr de savoir comment faire correspondre plusieurs modèles à la fois. Quelqu'un peut-il me dire comment nous le faisons efficacement?

17
Patan

Si vous n’avez que quelques regex et qu’ils sont tous connus au moment de la compilation, cela peut suffire:

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

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

S'il y en a plus, ou s'ils sont chargés au moment de l'exécution, utilisez une liste de modèles:

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


for (Pattern rx : rxs) if (rx.matcher(input).matches()) return true;
return false;
22
Marko Topolnik

vous pouvez créer un grand regex avec ceux-ci:

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

Je ne suis pas sûr de ce que signifie effectively, mais s'il s'agit de performances et que vous souhaitez vérifier beaucoup de chaînes, je m'attacherai à cela.

...
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;
}

Je ne sais pas comment cela affectera les performances, mais les combiner tous dans une expression rationnelle avec | pourrait également aider.

1
NeplatnyUdaj

Pour éviter de recréer des instances de classes Pattern et Matcher, vous pouvez en créer une et les réutiliser. Pour réutiliser la classe Matcher, vous pouvez utiliser la méthode reset(newInput). Attention : Cette approche n’est pas thread-safe. Utilisez-la uniquement lorsque vous êtes certain qu'un seul thread pourra utiliser cette méthode. Sinon, créez une instance distincte de Matcher pour chaque appel de méthode.

C'est l'un des exemples de code possibles

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
Pshemo

Voici une alternative ... Notez qu'une chose que cela ne fait pas est de les renvoyer dans un ordre spécifique Mais on pourrait le faire en triant par m.start () par exemple.

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();
        }

    }   
}
0
NobodyReally

comme cela a été expliqué dans ( Exécution de plusieurs modèles de regex sur String ), il est préférable de concaténer chaque regex en un grand regex et de n'exécuter qu'un seul matcher. C'est une grande amélioration si vous réutilisez souvent l'expression régulière. 

0
SkateScout