2010-08-12 4 views
24

Dites par exemple que j'ai la chaîne suivante "one two(three) (three) four five" et je veux remplacer "(three)" par "(four)" mais pas dans les mots. Comment je le ferais?expressions de limite de mots Regex

Fondamentalement, je veux faire un regex remplacer et finissent par la chaîne suivante:

"one two(three) (four) four five" 

J'ai essayé l'expression rationnelle suivante, mais il ne fonctionne pas:

@"\b\(three\)\b" 

Fondamentalement, je suis écrire un code de recherche et de remplacement et donner à l'utilisateur les options habituelles pour faire correspondre le cas, le mot entier etc. Dans ce cas, l'utilisateur a choisi de faire correspondre des mots entiers mais je ne sais pas quel sera le texte recherché.

+0

Tout part et d'autre d'un (ou) sera automatiquement une limite de mot, parce que ce n'est pas entre deux caractères de mot – Gareth

Répondre

48

Votre problème vient d'une mauvaise compréhension de ce que signifie réellement \b. Certes, ce n'est pas évident.

La raison \b\(three\)\b ne correspond pas aux groupes de trois dans votre chaîne d'entrée est la suivante:

  • \b signifie: la frontière entre un caractère de mot et un caractère non-mot.
  • Des lettres (par exemple a-z) sont considérées comme caractères de mot.
  • Les signes de ponctuation tels que ( sont considérés comme caractères non-mots.

Voici votre chaîne d'entrée à nouveau, étiré un peu, et je l'ai marqué les endroits où \b matches:

o n e t w o (t h r e e) (t h r e e) f o u r f i v e 
↑  ↑ ↑  ↑ ↑   ↑  ↑   ↑ ↑  ↑ ↑  ↑ 

Comme vous pouvez le voir ici, il y a un \b entre « deux » et "(trois)", mais pas avant le second "(trois)".

La morale de l'histoire? La recherche de mots entiers n'a pas vraiment de sens si ce que vous recherchez n'est pas juste un mot (une série de lettres). Puisque vous avez des signes de ponctuation (parenthèses) dans votre chaîne de recherche, ce n'est pas un "mot". Si vous avez recherché un mot composé uniquement de caractères de mot, alors \b ferait ce que vous attendez.

Vous pouvez, bien sûr, utiliser un autre Regex pour correspondre à la chaîne que si elle entourée par des espaces ou se produit au début ou à la fin de la chaîne:

(^|\s)\(three\)(\s|$) 

, le problème est cependant, Bien sûr, si vous cherchez "trois" (sans les parenthèses), il ne trouvera pas celui de "(trois)" parce qu'il n'a pas d'espace autour de lui, même s'il s'agit en fait d'un mot entier.

Je pense que la plupart des éditeurs de texte (y compris Visual Studio) utiliseront \b uniquement si votre chaîne de recherche commence réellement et/ou se termine par un mot:

var pattern = Regex.Escape(searchString); 
if (Regex.IsMatch(searchString, @"^\w")) 
    pattern = @"\b" + pattern; 
if (Regex.IsMatch(searchString, @"\w$")) 
    pattern = pattern + @"\b"; 

De cette façon, ils trouveront « (trois) » même si vous sélectionnez "mots entiers seulement".

+0

Cela n'a peut-être pas de sens mais c'est comme ça Je voudrais que ça marche. As-tu des idées sur comment je pourrais faire ça? Fondamentalement, je voudrais imiter la fonctionnalité de recherche et de remplacement au sein de Visual Studio. – CroweMan

+0

@CroweMan: Vous vous contredisez. Vous avez dit "Je ne veux pas" deux (trois) "à remplacer", mais Visual Studio le fait. – Timwi

+0

Merci beaucoup. Tu es une étoile! – CroweMan

-1

Comme Gopi dit, mais (théoriquement) la capture ne (three) pas two(three):

string input = "one two(three) (three) four five"; 

string output = input.Replace(" (three) ", " (four) "); 

Quand je teste, je reçois: "one two(three) (four) four five" Rappelez-vous simplement que l'espace blanc est un caractère de chaîne, aussi, donc il peut également être remplacé. Si je l'ai fait:

//use same input 
string output = input.Replace(" ", ";"); 

Je me one;two(three);(three);four;five"

+0

le problème est que l'utilisateur entre dans le texte dans une boîte de recherche et de remplacement et ils ont sélectionné «correspondre à des mots entiers». Je dois donc utiliser quelque chose d'intelligent comme des expressions régulières et je ne peux pas simplement ajouter un "" avant ou après l'expression car le caractère procédant pourrait être un ',' ou quelque chose d'autre – CroweMan

0

Je suis récemment tombé sur un problème similaire en javascript essayant de faire correspondre des termes avec un caractère '$' principal seulement en tant que mots séparés, par ex. si « FUZZ » chaud $ =, alors:

"some $hot $hotel bird$hot pellets" ---> "some FUZZ $hotel bird$hot pellets" 

Le regex /\b\$hot\b/g (ma première estimation) ne fonctionne pas pour la même raison, les parens ne correspondaient pas à la question initiale - comme des caractères non mot, il n'y a limite de mot/non-mot qui les précède avec un espace ou un début de chaîne.

Cependant, le regex /\B\$hot\b/g-t match, qui montre que les positions pas marqués en excellent exemple de @ Timwi correspondent le terme \ B. Ce n'était pas intuitif pour moi parce que ") (" n'est pas fait de caractères de mots regex. Mais je suppose que puisque \ B est une inversion de la classe \ b, il ne doit pas être des caractères de mot, il doit juste être pas-pas-caractères de mot :)

Questions connexes