2012-05-09 4 views
16

J'ai une liste d'environ 120 000 mots anglais (essentiellement chaque mot de la langue).Correspondance générique Expression régulière

J'ai besoin d'une expression régulière qui permette de rechercher à travers ces mots en utilisant des caractères génériques, a.k.a. * et ?.

Quelques exemples:

  • si les recherches des utilisateurs pour m?st*, il correspondraient par exemple master ou mister ou mistery.
  • si les recherches des utilisateurs pour *ind (tout mot se terminant par ind), il correspondraient wind ou bind ou blind ou grind.

Maintenant, la plupart des utilisateurs (en particulier ceux qui ne sont pas familiers avec les expressions régulières) savent que ? est un remplacement pour exactement 1 caractère, alors que * est un remplacement pour 0, 1 ou plusieurs caractères. Je veux absolument construire ma fonction de recherche basée sur ceci.

Mes questions sont: Comment puis-je convertir ce que l'utilisateur tape (m?st* par exemple) en une expression régulière? J'ai cherché sur le web (y compris évidemment ce site) et tout ce que j'ai pu trouver, ce sont des tutoriels qui essayaient de m'apprendre trop ou des questions qui étaient assez similaires, mais pas assez pour apporter une réponse à mon propre problème. Tout ce que j'ai pu comprendre, c'est que je dois remplacer ? par .. Donc m?st* devient m.st*. Cependant, je n'ai aucune idée de quoi remplacer * avec.

Toute aide serait grandement appréciée. Je vous remercie. PS: Je suis totalement nouveau pour les expressions régulières. Je sais à quel point ils peuvent être puissants, mais je sais aussi qu'ils peuvent être très difficiles à apprendre. Je n'ai donc jamais pris le temps de le faire ...

+1

duplication possible de [Existe-t-il un équivalent de java.util.regex pour les modèles de type "glob"?] (Http://stackoverflow.com/questions/1247772/is-there-an-equivalent-of-java- util-regex-for-glob-type-patterns) – NPE

+2

Gardez à l'esprit que tous les autres caractères regex * qui peuvent apparaître dans votre requête devront également être échappés. Si quelqu'un tape '^ \ w..', vous ne voulez probablement pas passer cela à votre moteur d'expressions régulières dans sa forme brute – Gareth

+0

@Gareth Merci, je m'en souviendrai. –

Répondre

15

Sauf si vous voulez un comportement drôle, je vous recommande d'utiliser \w au lieu de .

. matchs blancs et d'autres symboles non-mot, que vous pourriez ne pas vouloir qu'il fasse.

Je remplacerais ? avec \w et remplacer * avec \w*

Aussi, si vous voulez * pour correspondre à au moins un caractère, le remplacer par \w+ à la place. Cela signifierait que ben* correspondrait et bending mais pas ben - c'est à vous de décider, tout dépend de vos besoins.

+0

La question dit "while' * 'est un remplacement pour 0, 1 ou plusieurs caractères" – Gareth

+2

@Gareth ya, j'ai vu ça. Je pensais que je voudrais offrir l'info supplémentaire. – gnomed

+0

@gnomed Pourquoi '\ w' est-il meilleur que' .'? –

1

. est une expression qui correspond à un caractère, comme vous l'avez découvert. Dans vos heures de recherche, vous avez sans aucun doute également trébuché *, qui est un opérateur de répétition qui, lorsqu'il est utilisé après une expression correspond l'expression précédente zéro ou plusieurs fois dans une ligne. Donc l'équivalent de ce que vous voulez dire par * est de mettre ces deux éléments ensemble: .*.

Cela signifie alors "n'importe quel caractère zéro ou plusieurs fois".

Voir le Regex Tutorial on repetition operators.

+0

Ouais, je sais, je ne suis pas très bon pour trouver des choses sur le web, surtout si je suis totalement étrange pour eux :). –

1

Remplacez * par .* (l'équivalent regex de «0 ou plus de n'importe quel caractère»).

6

Remplacez ? par . et * par .*.

2
  1. Remplacer tout '?' avec des caractères '\ w'
  2. remplacer toutes les '*' avec les caractères '\ w *'

L'opérateur '*' répète l'élément précédent '' (n'importe quel caractère) 0 ou plusieurs fois.

Ceci suppose qu'aucun des mots ne contient '.', '*' Et '?'.

Ceci est une bonne référence

http://www.regular-expressions.info/reference.html

0
function matchWild(wild,name) 
{ 
    if (wild == '*') return true; 

    wild = wild.replace(/\./g,'\\.'); 
    wild = wild.replace(/\?/g,'.'); 
    wild = wild.replace(/\\/g,'\\\\'); 
    wild = wild.replace(/\//g,'\\/'); 
    wild = wild.replace(/\*/g,'(.+?)'); 

    var re = new RegExp(wild,'i'); 
    return re.test(name); 
} 
2

Voici un moyen de transformer wildcard regex:

  1. Prepend tous special characters([{\^- = $! |]}.. + avec \ - de sorte qu'ils soient mis en correspondance en tant que caractères et ne rendent pas l'expérience utilisateur inattendue. Vous pouvez également l'inclure dans \ Q (qui commence la citation) et \ E (qui le termine). Voir aussi le paragraphe sur la sécurité.
  2. Remplacer * joker par \ S *
  3. Remplacer? caractère générique avec \ S?
  4. Facultatif: ajouter un motif à l'aide de ^ - Cela permet d'appliquer une correspondance exacte avec le début.
  5. Facultativement: ajoutez $ pour appliquer une correspondance exacte à la fin.

    \ S - représente le caractère non-espace, qui se produit zéro ou plusieurs fois.

Considérez using reluctant (non-greedy) quantifiers si vous avez des caractères pour correspondre après * ou +. Cela peut être fait en ajoutant ? après * ou + comme ceci: \ S *? et \ S * +?

Tenir compte sécurité: l'utilisateur envoie votre code à exécuter (car regex est une sorte d'un code aussi, et la chaîne de l'utilisateur est utilisé comme regex). Vous devez éviter de passer une regex non échappée à d'autres parties de l'application et ne l'utiliser que pour filtrer les données récupérées par d'autres moyens. Parce que si vous faites l'utilisateur peut affecter la vitesse de votre code en fournissant regex différent avec une chaîne générique - cela pourrait être utilisé dans les attaques DoS.

exemple pour montrer des vitesses d'exécution des modèles similaires:

seq 1 50000000 > ~/1 
du -sh ~/1 
563M 
time grep -P '.*' ~/1 &>/dev/null 
6.65s 
time grep -P '.*.*.*.*.*.*.*.*' ~/1 &>/dev/null 
12.55s 
time grep -P '.*..*..*..*..*.*' ~/1 &>/dev/null 
31.14s 
time grep -P '\S*.\S*.\S*.\S*.\S*\S*' ~/1 &>/dev/null 
31.27s 

Je vous suggère de ne pas utiliser * simplement parce qu'il peut correspondre à quelque chose, et généralement les choses sont séparés par des espaces..

0

C'est ce que j'utilise:

String wildcardToRegex(String wildcardString) { 
    // The 12 is arbitrary, you may adjust it to fit your needs depending 
    // on how many special characters you expect in a single pattern. 
    StringBuilder sb = new StringBuilder(wildcardString.length() + 12); 
    sb.append('^'); 
    for (int i = 0; i < wildcardString.length(); ++i) { 
     char c = wildcardString.charAt(i); 
     if (c == '*') { 
      sb.append(".*"); 
     } else if (c == '?') { 
      sb.append('.'); 
     } else if ("\\.[]{}()+-^$|".indexOf(c) >= 0) { 
      sb.append('\\'); 
      sb.append(c); 
     } else { 
      sb.append(c); 
     } 
    } 
    sb.append('$'); 
    return sb.toString(); 
} 

Liste des caractères spéciaux de https://stackoverflow.com/a/26228852/1808989.

Questions connexes