2009-08-24 6 views
69

Ich benutze Java Regexes in Java 1.6 (unter anderem um numerische Ausgaben zu parsen) und finde keine genaue Definition von \b ("Wortgrenze"). Ich hatte angenommen, dass -12 wäre ein "Integer-Wort" (mit \b\-?\d+\b übereinstimmen), aber es scheint, dass dies nicht funktioniert. Ich wäre dankbar, wenn ich wissen würde, wie man durch Leerzeichen getrennte Zahlen findet.Was ist eine Wortgrenze in Regexes?

Beispiel:

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

Das gibt:

true 
false 
true 
+0

können Sie ein kleines Beispiel mit Eingang und Ausgang erwartet posten? –

+0

Wird versuchen, einen zu konstruieren –

+0

Beispiel \t Muster pattern = Pattern.compile ("\\ s * \\ b \\ -? \\ d + \\ s *"); \t Zeichenfolge plus = "12"; \t System.out.println ("" + pattern.matcher (plus) .matches()); \t String minus = "-12"; \t System.out.println ("" + pattern.matcher (minus) .matches()); \t pattern = Pattern.compile ("\\ s * \\ -? \\ d + \\ s *"); \t System.out.println ("" + pattern.matcher (minus) .matches()); gibt: true false true –

Antwort

48

eine Wortgrenze, in den meisten regex Dialekten, ist eine Position zwischen \w und \W (non-Wort char), oder am Anfang oder am Ende einer Zeichenkette, wenn es beginnt oder endet (jeweils) mit einem Wortzeichen ([0-9A-Za-z_]).

Also, in der Zeichenfolge "-12", würde es vor der 1 oder nach der 2. übereinstimmen. Der Strich ist kein Wort Zeichen.

+17

Korrektamundo. '\ b' ist eine Assertion mit der Breite null, die übereinstimmt, wenn auf der einen Seite' \ w' steht und auf der anderen Seite '\ W' steht oder die Position der Anfang oder das Ende der Zeichenkette ist. '\ w' ist willkürlich definiert als" Bezeichner "-Zeichen (Alnums und Unterstriche), nicht als etwas, das für Englisch besonders nützlich ist. – hobbs

+0

100% richtig. Entschuldigung dafür, dass du nicht nur deine kommentiert hast. Ich habe mich gedrängt, bevor ich deine Antwort gesehen habe. –

+1

aus Gründen des Verständnisses, ist es möglich, die Regex '\ bhello \ b' ohne Verwendung von' \ b' (mit '\ w',' \ W' und anderen) zu schreiben? –

0

Ich denke, es ist die Grenze ist (das heißt Zeichen nach) des letzten Spiels oder am Anfang oder Ende des Strings.

+1

Sie denken an '\ G': entspricht dem Anfang der Zeichenfolge (wie' \ A') beim ersten Spielversuch; danach stimmt es mit der Position überein, wo das vorherige Spiel endete. –

1

Ich glaube, dass Ihr Problem aufgrund der Tatsache, dass - kein Wort Charakter ist. Daher wird die Wortgrenze nach der - übereinstimmen und wird daher nicht erfasst. Wortgrenzen stimmen vor dem ersten und nach dem letzten Wort in einer Zeichenkette überein, ebenso wie jede Stelle, an der sich davor ein Wortzeichen oder Nicht-Wortzeichen befindet, und danach das Gegenteil. Beachten Sie auch, dass die Wortgrenze eine Null-Breite-Übereinstimmung ist.

Eine mögliche Alternative ist

(?:(?:^|\s)-?)\d+\b 

Dadurch werden alle Zahlen übereinstimmen mit einem Leerzeichen beginnen und einem optionalen Bindestrich und an einer Wortgrenze endet. Es wird auch eine Zahl übereinstimmen, die am Anfang der Zeichenfolge beginnt.

4

Überprüfen Sie die Dokumentation auf Randbedingungen aus:

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

prüfen diese Probe aus:

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

Wenn Sie es ausdrucken, feststellen, dass der Ausgang ist dies:

[Ich fand den Wert - in meiner Zeichenfolge.]

Dies bedeutet, dass das Zeichen "-" nicht als Wortgrenze erkannt wird, da es nicht als Wortzeichen betrachtet wird. Sieht so aus als ob @brianary mich irgendwie bis zum Schlag schlägt, also bekommt er eine Stimme.

13

eine Wortgrenze kann in einem von drei Positionen auftreten:

  1. vor dem ersten Zeichen in der Zeichenfolge, wenn das erste Zeichen ein Wortzeichen ist.
  2. Nach dem letzten Zeichen in der Zeichenfolge, wenn das letzte Zeichen ein Wortzeichen ist.
  3. Zwischen zwei Zeichen in der Zeichenfolge, wobei eins ein Wortzeichen und das andere kein Wortzeichen ist.

Wortzeichen sind alphanumerisch; ein Minuszeichen ist nicht. entnommen von Regex Tutorial.

3

Eine Wortgrenze ist eine Position, der ein Wortzeichen vorangestellt ist und nicht gefolgt von einem oder gefolgt von einem Wortzeichen, dem kein vorangestelltes Zeichen vorangestellt ist.

+0

Dies ist die beste Erklärung. –

4

Ich spreche über, was \b-Regex Grenzen tatsächlich sind here.

Die kurze Geschichte ist, dass sie bedingt sind. Ihr Verhalten hängt davon ab, was sie neben sich haben.

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

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

Manchmal ist das nicht das, was Sie wollen. Siehe meine andere Antwort für die Ausarbeitung.

4

Ich lief in einem noch schlimmeren Problem, wenn Text für Wörter wie .NET Suche, C++, C# und C. Sie würden denken, dass Computerprogrammierer es besser wissen würden, als eine Sprache zu benennen, für die es schwer ist, reguläre Ausdrücke zu schreiben.

Auf jeden Fall ist es das, was ich herausgefunden (zusammengefasst meist aus http://www.regular-expressions.info, das ist ein großer Standort ist): In den meisten Aromen von regex, Zeichen, die durch die Kurz Hand Zeichenklasse abgestimmt sind \w sind die Zeichen, die als behandelt werden Wortzeichen nach Wortgrenzen. Java ist eine Ausnahme. Java unterstützt Unicode für \b, aber nicht für \w. (Ich bin mir sicher, dass es zu der Zeit einen guten Grund dafür gab).

Die \w steht für "word character". Es entspricht immer den ASCII-Zeichen [A-Za-z0-9_]. Beachten Sie die Angabe von Unterstrich und Ziffern (aber nicht Bindestrich!). In den meisten Varianten, die Unicode unterstützen, enthält \w viele Zeichen aus anderen Skripts. Es gibt viele Unstimmigkeiten darüber, welche Zeichen tatsächlich enthalten sind. Buchstaben und Ziffern aus alphabetischen Schriften und Ideogrammen sind im Allgemeinen enthalten. Connector-Interpunktion mit Ausnahme des Unterstrichs und numerische Symbole, die keine Ziffern sind, können enthalten sein oder nicht. XML-Schema und XPath enthalten sogar alle Symbole in \w. Aber Java, JavaScript und PCRE stimmen nur mit ASCII-Zeichen mit \w überein.

Weswegen Java-basierte Regex sucht nach C++, C# oder .NET (auch wenn Sie daran denken, die Zeit und Pluspunkte zu entkommen) durch die \b verschraubt sind.

Hinweis: Ich bin mir nicht sicher, was ich bei Textfehlern tun soll, z. B. wenn jemand nach einer bestimmten Zeit am Ende eines Satzes keinen Platz eingibt. Ich habe es zugelassen, aber ich bin mir nicht sicher, ob es das Richtige ist.

Wie auch immer, in Java, wenn Sie Text für diese merkwürdig benannten Sprachen suchen, müssen Sie die \b durch vor und nach Leerzeichen und Interpunktionsbezeichner ersetzen. Zum Beispiel:

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

Dann in Ihrem Test oder Hauptfunktion:

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. Mein Dank an http://regexpal.com/ ohne wen die Regex-Welt sehr miserabel wäre!

+0

Ich hatte Mühe zu verstehen, warum ich 'C#' nicht zuordnen konnte, aber jetzt ist es klarer –

0

wenn Sie \\b(\\w+)+\\b verwenden, die genaue Übereinstimmung mit einem Wort, das nur Wortzeichen ([a-zA-Z0-9])

in Ihrem Fall bedeutet beispielsweise \\b am Anfang der Regex Einstellung wird -12 (mit Leerzeichen) akzeptieren aber auch hier wird es nicht akzeptieren -12 (ohne Leerzeichen)

Referenz meine Worte zu unterstützen: https://docs.oracle.com/javase/tutorial/essential/regex/bounds.html