Comment puis-je effectuer une correspondance partielle avec java.util.regex.*?

j'ai utilisé le java.util.regex.* classes pour L'Expression régulière en Java et tout bon jusqu'à présent. Mais aujourd'hui, j'ai une autre exigence. Par exemple, considérez que le modèle est "aabb". Maintenant, si la chaîne d'entrée est aa, elle ne correspondra certainement pas, cependant il y a toujours la possibilité que si j'ajoute bb elle devienne aabb et qu'elle corresponde. Cependant, si j'avais commencé par cc, peu importe ce que j'ajoute, il ne correspondrait jamais.

j'ai exploré la classe Pattern et Matcher mais n'ai pas trouvé moyen d'y parvenir.

L'entrée viendra de l'utilisateur et le système, il faudra attendre jusqu'modèle de matchs ou il n'égaleront jamais indépendamment de toute entrée supplémentaire.

Aucune idée?

Merci.

24
demandé sur Alan Moore 2010-03-18 14:01:20
la source

7 ответов

vous auriez dû regarder de plus près L'API Matcher; le hitEnd() méthode fonctionne exactement comme vous l'avez décrit:

import java.util.regex.*;

public class Test
{
  public static void main(String[] args) throws Exception
  {
    String[] ss = { "aabb", "aa", "cc", "aac" };
    Pattern p = Pattern.compile("aabb");
    Matcher m = p.matcher("");

    for (String s : ss) {
      m.reset(s);
      if (m.matches()) {
        System.out.printf("%-4s : match%n", s);
      }
      else if (m.hitEnd()) {
        System.out.printf("%-4s : partial match%n", s);
      }
      else {
        System.out.printf("%-4s : no match%n", s);
      }
    }
  }
}

sortie:

aabb : match
aa   : partial match
cc   : no match
aac  : no match

autant que je sache, Java est le seul langage qui expose cette fonctionnalité. Il y a aussi le requireEnd() méthode, qui vous dit si plus d'entrée pourrait transformer une correspondance en non-correspondance, mais je ne pense pas que ce soit pertinent dans votre cas.

les deux méthodes ont été ajoutées pour supporter la classe de Scanner, donc il peut appliquer des regexes à un flux sans exiger que tout le flux soit lu en mémoire.

34
répondu Alan Moore 2015-11-04 22:58:22
la source
Pattern p = Pattern.compile(expr);
Matcher m = p.matcher(string);
m.find();
11
répondu Jun D. Ouyang 2012-07-28 20:44:04
la source

Vous ne voulez donc pas savoir si une chaîne S correspond au regex, mais s'il pourrait y avoir une chaîne plus longue commençant par s qui correspondrait? Désolé, Regexes ne peut pas vous aider là-bas parce que vous n'obtenez pas d'accès à l'état interne du matcher; vous obtenez seulement le résultat booléen et tous les groupes que vous avez définis, de sorte que vous ne savez jamais pourquoi un match échoue.

si vous êtes prêt à pirater les bibliothèques JDK, vous pouvez étendre (ou probablement biffer) java.util.regex et donner plus informations sur le processus d'appariement. Si la correspondance échoue parce que l'entrée est 'used up', la réponse sera true; si elle a échoué en raison du caractère de la discrimination ou d'autres contrôles il serait false. Cela ressemble à beaucoup de travail, parce que votre problème est complètement à l'opposé de ce que regexes sont censés faire.

une autre option: peut-être Pouvez-vous simplement redéfinir la tâche de sorte que vous puissiez traiter l'entrée comme la regexp et match aabb contre *aa.**? Vous devez être prudent sur les regex métacaractères.

1
répondu Kilian Foth 2010-03-18 14:27:20
la source

pour l'exemple que vous donnez, vous pouvez essayer d'utiliser un anti-pattern pour disqualifier les résultats invalides. Par exemple" ^[^a] "vous dirait que vous êtes entré" C..."ne peut pas correspondre à votre modèle d'exemple de "aabb".

selon votre modèle, vous pouvez être en mesure de le briser en plus petits modèles pour vérifier et utiliser plusieurs matchers et ensuite définir leurs limites comme une correspondance se produit et vous déplacer à la suivante. Cette approche peut fonctionner mais si vous êtes modèle est complexe et peut avoir une longueur variable sous-parties vous pouvez finir par réimplémenter une partie du matcher dans votre propre code pour ajuster les limites possibles du match pour le rendre plus ou moins gourmand. Une idée générale de ce pseudo-code serait:

boolean match(String input, Matcher[] subpatterns, int matchStart, int matchEnd){
  matcher = next matcher in list;
  int stop = matchend;
  while(true){
    if matcher.matches input from matchstart -> matchend{
      if match(input, subpatterns, end of current match, end of string){
        return true;
      }else{
        //make this match less greedy
        stop--;
      }
    }else{
      //no match
      return false;
    }
  }
}

vous pourriez alors fusionner cette idée avec les anti-patterns, et avoir des anti-subpatterns et après chaque match subpattern vous vérifiez le prochain anti-pattern, si cela correspond vous savez que vous avez échoué, sinon continuer le motif correspondant. Vous voudriez probablement retourner quelque chose comme un enum au lieu d'un booléen (i.e. ALL_MATCHED, PARTIAL_MATCH, ANTI_PATTERN_MATCH, ...)

encore une fois selon la complexité de votre modèle réel que vous essayez d'apparier l'écriture des sous-modèles / anti-modèle appropriés peut être difficile, voire impossible.

0
répondu M. Jessup 2010-03-18 14:52:21
la source

une façon de faire ceci est de parser votre regex dans une séquence de sous-regexes, puis de les remonter d'une manière qui vous permet de faire des correspondances partielles; par exemple "abc" est composé de 3 sous-regexes "a", "b" et "c" que vous pouvez ensuite remonter comme un "b*(c)?)?".

les choses deviennent plus compliquées lorsque le regex input contient alternation et groups, mais la même approche générale devrait fonctionner.

Le problème avec cette approche est que la regex est plus complexe, et pourrait conduire à un retour en arrière excessif pour les regexes d'entrée complexes.

0
répondu Stephen C 2010-03-18 15:48:43
la source

si vous rendez chaque caractère du regex optionnel et relâchez les contraintes de multiplicité, vous obtenez en quelque sorte ce que vous voulez. Exemple si vous avez un filtre aa(abc)+bbbb", vous pouvez avoir un 'correspondance' motif 'un?un?(une?b?c?) * b?b?b?b?'.

cette façon mécanique de produire le motif de correspondance possible ne couvre pas les constructions avancées comme les réf avant et arrière cependant.

0
répondu ddimitrov 2010-03-18 15:59:04
la source

Vous pourriez être en mesure d'accomplir ceci avec une machine d'état (http://en.wikipedia.org/wiki/State_machine). Avoir vos états/transitions représentent d'entrée valide et un état d'erreur. Vous pouvez alors alimenter la machine d'état d'un caractère (éventuellement la sous-chaîne en fonction de vos données) à la fois. À tout moment, vous pouvez vérifier si votre état de la machine est dans l'état d'erreur. Si elle n'est pas dans l'état d'erreur, alors vous savez que l'avenir peut encore correspondre. Si elle est dans l'état d'erreur alors vous savez que quelque chose a déjà échoué et toute entrée future ne rendra pas la chaîne valide.

-1
répondu brainimus 2010-03-18 15:13:05
la source

Autres questions sur