2009-08-24 13 views
69

Utilizzo espressioni regex Java in Java 1.6 (tra l'altro per analizzare l'output numerico) e non riesco a trovare una definizione precisa di \b ("limite di parole"). Avevo ipotizzato che -12 sarebbe una "parola intera" (corrispondente a \b\-?\d+\b) ma sembra che ciò non funzioni. Sarei grato di sapere come allineare i numeri separati dallo spazio.Che cos'è un limite di parola nelle espressioni regolari?

Esempio:

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

Ciò restituisce:

true 
false 
true 
+0

Puoi pubblicare un piccolo esempio con ingresso e uscita prevista? –

+0

Proverà a costruire uno –

+0

Esempio \t Pattern pattern = Pattern.compile ("\\ s * \\ b \\ -? \\ d + \\ s *"); \t Stringa più = "12"; \t System.out.println ("" + pattern.matcher (plus) .matches()); \t Stringa meno = "-12"; \t System.out.println ("" + pattern.matcher (meno) .matches()); \t pattern = Pattern.compile ("\\ s * \\ -? \\ d + \\ s *"); \t System.out.println ("" + pattern.matcher (meno) .matches()); corrisponde a true false true –

risposta

48

Un limite di parola, nella maggior parte dei dialetti regex, è una posizione tra \w e \W (char non-parola), o all'inizio o alla fine di una stringa se inizia o (rispettivamente) termina con un carattere di parola ([0-9A-Za-z_]).

Quindi, nella stringa "-12", corrisponderebbe prima dell'1 o dopo 2. Il trattino non è un carattere di parola.

+17

Correctamundo. '\ b' è un'asserzione di larghezza zero che corrisponde se c'è' \ w' su un lato, e o c'è '\ W' sull'altro o la posizione sta iniziando o alla fine della stringa. '\ w' è definito arbitrariamente come caratteri" identificatori "(alnums e underscore), non come qualcosa di particolarmente utile per l'inglese. – hobbs

+0

100% corretto. Mi scuso per non aver solo commentato il tuo. Ho premuto invio prima di vedere la tua risposta. –

+1

per motivi di comprensione, è possibile riscrivere la regex '\ bhello \ b' senza usare' \ b' (usando '\ w',' \ W' e altri)? –

0

penso che sia il confine (cioè carattere che segue) dell'ultimo incontro o all'inizio o alla fine della stringa.

+1

Stai pensando a '\ G': corrisponde all'inizio della stringa (come' \ A') al primo tentativo di corrispondenza; dopodiché corrisponde alla posizione in cui è terminata la partita precedente. –

1

Credo che il tuo problema sia dovuto al fatto che - non è un carattere di parola. Pertanto, il confine della parola corrisponderà dopo lo - e quindi non lo catturerà. I contorni di parola corrispondono prima al primo e dopo l'ultimo carattere di una stringa, così come qualsiasi altro punto in cui prima si tratta di un carattere di parola o di un carattere diverso da una parola, e dopo è il contrario. Si noti inoltre che il limite della parola è una corrispondenza di larghezza zero.

Una possibile alternativa è

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

Questo corrisponderà a qualsiasi numeri che iniziano con un carattere di spazio e di un cruscotto opzionale, e termina ad un limite di una parola. Corrisponde anche a un numero che inizia all'inizio della stringa.

4

controllare la documentazione sulle condizioni al contorno:

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

Partenza questo campione:

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

Quando si stampa fuori, notare che l'uscita è questa:

[Ho trovato il valore -, nella mia stringa.]

Ciò significa che il carattere "-" non viene rilevato come al limite di una parola perché non è considerato un carattere di parola. Sembra che @brianary mi picchi per il pugno, quindi ottiene un voto positivo.

13

Un limite di parola può verificarsi in una delle tre posizioni:

  1. Prima del primo carattere della stringa, se il primo carattere è un carattere di parola.
  2. Dopo l'ultimo carattere nella stringa, se l'ultimo carattere è un carattere di parola.
  3. Tra due caratteri nella stringa, dove uno è un carattere di parola e l'altro non è un carattere di parola.

I caratteri di parole sono alfanumerici; un segno meno non lo è. Tratto da Regex Tutorial.

3

Un limite di parola è una posizione preceduta da un carattere di parola e non seguita da uno, o seguita da un carattere di parola e non preceduta da uno.

+0

Questa è la spiegazione migliore. –

4

Parlo di quello che i contorni di regex in stile \b sono in realtà here.

Il racconto è che sono condizionale. Il loro comportamento dipende da cosa sono accanto.

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

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

A volte questo non è quello che vuoi. Vedi la mia altra risposta per l'elaborazione.

4

mi sono imbattuto in un problema ancora peggio quando la ricerca di testo per parole come .NET, C++, C# e C. Si potrebbe pensare che i programmatori di computer saprebbero meglio che nominare un linguaggio per cui è difficile scrivere espressioni regolari.

Comunque, questo è quello che ho scoperto (riassunto per lo più da http://www.regular-expressions.info, che è un ottimo sito): Nella maggior parte dei sapori della regex, personaggi che è compensata dalla classe del personaggio a breve mano \w sono i personaggi che sono trattati come parola caratteri per parola. Java è un'eccezione. Java supporta Unicode per \b ma non per \w. (Sono sicuro che c'era una buona ragione per questo in quel momento).

\w indica "carattere parola". Corrisponde sempre ai caratteri ASCII [A-Za-z0-9_]. Notare l'inclusione del carattere di sottolineatura e delle cifre (ma non il trattino!). Nella maggior parte dei gusti che supportano Unicode, \w include molti caratteri di altri script. C'è molta incongruenza su quali personaggi sono effettivamente inclusi. Sono generalmente incluse lettere e cifre di script alfabetici e ideogrammi. La punteggiatura del connettore diversa dal carattere di sottolineatura e dai simboli numerici che non sono cifre potrebbe essere inclusa o meno. XML Schema e XPath includono anche tutti i simboli in \w. Ma Java, JavaScript e PCRE corrispondono solo caratteri ASCII con \w.

Ecco perché basata su Java ricerche regex per C++, C# o .NET (anche quando si ricorda di fuggire il periodo e vantaggi) sono avvitate dal \b.

Nota: non sono sicuro di cosa fare per errori di testo, come quando qualcuno non mette uno spazio dopo un punto alla fine di una frase. L'ho permesso, ma non sono sicuro che sia necessariamente la cosa giusta da fare.

Ad ogni modo, in Java, se si cercano testi per quelle lingue con nomi strani, è necessario sostituire lo \b con i designatori di spazi bianchi e punteggiatura prima e dopo. Per esempio:

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

Poi, nel tuo test o funzione 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. I miei ringraziamenti allo http://regexpal.com/ senza il quale il mondo delle regex sarebbe molto miserabile!

+0

Ho faticato a capire perché non potevo associare 'C#' ma ora è più chiaro –

0

quando si utilizza \\b(\\w+)+\\b che significa corrispondenza esatta con una parola che contiene solo caratteri di parola ([a-zA-Z0-9])

nel tuo caso per l'impostazione \\b all'inizio di regex accetterà -12 (con spazio) esempio, ma ancora una volta non accetterà -12 (senza spazio)

di riferimento per sostenere le mie parole: https://docs.oracle.com/javase/tutorial/essential/regex/bounds.html

Problemi correlati