198 votes

Qu'est ce qu'une frontière de mot dans regexes?

Je suis à l'aide de Java regexes dans la version 1.6 de Java (notamment pour analyser sortie numérique) et impossible de trouver une définition précise de la \b ("mot"). J'avais supposé que "-12" serait un "mot entier" (adapté en \b\-?\d+\b), mais il semble que cela ne fonctionne pas. Je serais heureux de connaître les moyens de correspondance, séparés par des espaces numéros.

Exemple:

    Pattern pattern = Pattern.compile("\\s*\\b\\-?\\d+\\s*");
    String plus = " 12 ";
    System.out.println(""+pattern.matcher(plus).matches());
    String minus = " -12 ";
    System.out.println(""+pattern.matcher(minus).matches());
    pattern = Pattern.compile("\\s*\\-?\\d+\\s*");
    System.out.println(""+pattern.matcher(minus).matches());

retourne

true
false
true

146voto

brianary Points 2584

Une limite de mot, dans la plupart des regex dialectes, est une position entre \w et \W (non-mot char), ou au début ou à la fin d'une chaîne si elle commence ou se termine (respectivement), avec un caractère de mot ([0-9A-Za-z_]).

Ainsi, dans la chaîne de caractères "-12", il serait de match avant le 1er ou après l'2. Le tableau de bord n'est pas un caractère de mot.

33voto

WolfmanDragon Points 3328

Une limite de mot est une position. Il peut être l'une des trois positions.

  1. Avant le premier caractère de la chaîne, si le premier caractère est un caractère de mot.
  2. Après le dernier caractère de la chaîne, si le dernier caractère est un caractère de mot.
  3. Entre deux caractères dans la chaîne, où l'on est un caractère de mot et l'autre n'est pas un caractère de mot.

Mot de caractères sont des caractères alpha-numériques. Un mini signe est un non mot de caractères. Prises de Regex Tutoriel.

10voto

tchrist Points 47116

Je parle de ce que \b-style regex limites sont en fait ici.

La petite histoire c'est qu'ils sont conditionnelles. Leur comportement dépend de ce qu'ils sont à côté.

# same as using a \b before:
(?(?=\w) (?<!\w)  | (?<!\W) )

# same as using a \b after:
(?(?<=\w) (?!\w)  | (?!\W)  )

Parfois, ce n'est pas ce que vous voulez. Voir mon autre réponse pour l'élaboration.

7voto

Tihamer Points 51

Je suis tombé sur un même pire problème lors de la recherche de texte pour des mots comme .NET, C++, C#, et C. on pourrait penser que les programmeurs savent mieux que de nom une langue quelque chose qui est difficile à écrire des expressions régulières pour.

De toute façon, c'est ce que j'ai trouvé (résumé la plupart de http://www.regular-expressions.info, qui est un excellent site): Dans la plupart des saveurs de regex, les personnages qui sont mis en correspondance par la court de main de la classe de caractères \w sont les personnages qui sont traités comme des caractères de mot par mot les limites. Java est une exception. Java supporte Unicode pour l' \b mais pas pour \w. (Je suis sûr qu'il y a une bonne raison pour ça à l'époque).

Le \w signifie "caractère de mot". Il correspond toujours les caractères ASCII [A-Za-z0-9_]. Avis l'inclusion de le trait de soulignement et des chiffres (mais pas de tiret!). Dans la plupart des saveurs qui s'en charge Unicode, \w comprend le nombre de caractères à partir d'autres scripts. Il y a beaucoup d'incohérence à propos de laquelle les caractères sont inclus. Les lettres et les chiffres de alphabétiques des scripts et des idéogrammes sont généralement inclus. Connecteur de ponctuation autre que le trait de soulignement et numérique les symboles qui ne sont pas les chiffres peuvent ou peuvent ne pas être inclus. Le Schéma XML et XPath même inclure tous les symboles de \w. Mais Java, JavaScript, et PCRE match uniquement des caractères ASCII avec \w.

C'est pourquoi Java regex recherches pour C++, C# ou .NET (même si vous n'oubliez pas de s'échapper de la période et plus) sont vissés par le \b.

Note: je ne suis pas sûr de quoi faire de fautes dans le texte, comme quand quelqu'un n'a pas mis un espace après un point à la fin d'une phrase. - Je le droit pour elle, mais je ne suis pas sûr que c'est forcément la bonne chose à faire.

De toute façon, en Java, si vous êtes à la recherche d'un texte pour le ces étranges nommé langues, vous devez remplacer le \b avec avant et après les espaces et les signes de ponctuation les désignateurs. Par exemple:

public static String grep(String regexp, String multiLineStringToSearch) {
    String result = "";
    String[] lines = multiLineStringToSearch.split("\\n");
    Pattern pattern = Pattern.compile(regexp);
    for (String line : lines) {
        Matcher matcher = pattern.matcher(line);
        if (matcher.find()) {
            result = result + "\n" + line;
        }
    }
    return result.trim();
}

Ensuite, dans votre test ou de la fonction principale:

    String beforeWord = "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|^)";   
    String afterWord =  "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|$)";
    text = "Programming in C, (C++) C#, Java, and .NET.";
    System.out.println("text="+text);
    // Here is where Java word boundaries do not work correctly on "cutesy" computer language names.  
    System.out.println("Bad word boundary can't find because of Java: grep with word boundary for .NET="+ grep("\\b\\.NET\\b", text));
    System.out.println("Should find: grep exactly for .NET="+ grep(beforeWord+"\\.NET"+afterWord, text));
    System.out.println("Bad word boundary can't find because of Java: grep with word boundary for C#="+ grep("\\bC#\\b", text));
    System.out.println("Should find: grep exactly for C#="+ grep("C#"+afterWord, text));
    System.out.println("Bad word boundary can't find because of Java:grep with word boundary for C++="+ grep("\\bC\\+\\+\\b", text));
    System.out.println("Should find: grep exactly for C++="+ grep(beforeWord+"C\\+\\+"+afterWord, text));

    System.out.println("Should find: grep with word boundary for Java="+ grep("\\bJava\\b", text));
    System.out.println("Should find: grep for case-insensitive java="+ grep("?i)\\bjava\\b", text));
    System.out.println("Should find: grep with word boundary for C="+ grep("\\bC\\b", text));  // Works Ok for this example, but see below
    // Because of the stupid too-short cutsey name, searches find stuff it shouldn't.
    text = "Worked on C&O (Chesapeake and Ohio) Canal when I was younger; more recently developed in Lisp.";
    System.out.println("text="+text);
    System.out.println("Bad word boundary because of C name: grep with word boundary for C="+ grep("\\bC\\b", text));
    System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));
    // Make sure the first and last cases work OK.

    text = "C is a language that should have been named differently.";
    System.out.println("text="+text);
    System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));

    text = "One language that should have been named differently is C";
    System.out.println("text="+text);
    System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));

    //Make sure we don't get false positives
    text = "The letter 'c' can be hard as in Cat, or soft as in Cindy. Computer languages should not require disambiguation (e.g. Ruby, Python vs. Fortran, Hadoop)";
    System.out.println("text="+text);
    System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));

P. S. Mes remerciements à http://regexpal.com/ sans qui la regex monde serait très malheureux!

4voto

Brent Nash Points 6337

Consultez la documentation sur les conditions aux limites:

http://java.sun.com/docs/books/tutorial/essential/regex/bounds.html

Découvrez cet échantillon:

public static void main(final String[] args)
    {
    	String x = "I found the value -12 in my string.";
    	System.err.println(Arrays.toString(x.split("\\b-?\\d+\\b")));
    }

Lorsque vous imprimez, vous remarquerez que la sortie est ceci:

[J'ai trouvé la valeur, dans ma chaîne.]

Cela signifie que le caractère "-" n'est pas détectée comme étant à la limite d'un mot, car il n'est pas considéré comme un caractère de mot. Ressemble @brianary un peu me battre pour le punch, de sorte qu'il obtient un vote.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X