O que é um limite de palavras em regex?

137

Estou usando regexes Java no Java 1.6 (para analisar a saída numérica, entre outros propósitos) e não consigo encontrar uma definição precisa de \b("limite de palavras"). Eu tinha assumido que -12seria uma "palavra inteira" (correspondida por \b\-?\d+\b), mas parece que isso não funciona. Ficaria muito grato em saber como combinar números separados por espaço.

Exemplo:

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

Isso retorna:

true
false
true
peter.murray.rust
fonte
Você pode postar um pequeno exemplo com entrada e saída esperada?
Brent escreve código
Exemplo Padrão padrão = Pattern.compile ("\\ s * \\ b \\ -? \\ d + \\ s *"); String mais = "12"; System.out.println ("" + padrão.matcher (mais) .matches ()); String menos = "-12"; System.out.println ("" + padrão.matcher (menos) .matches ()); pattern = Pattern.compile ("\\ s * \\ -? \\ d + \\ s *"); System.out.println ("" + padrão.matcher (menos) .matches ()); dá: verdadeiro falso verdadeiro
peter.murray.rust

Respostas:

97

Um limite de palavras, na maioria dos dialetos regex, é uma posição entre \we \W(caractere não-palavra), ou no início ou no final de uma sequência, se ela começa ou termina (respectivamente) com um caractere de palavra ( [0-9A-Za-z_]).

Portanto, na sequência "-12", ela corresponderia antes do 1 ou após o 2. O traço não é um caractere de palavra.

brianary
fonte
35
Correctamundo. \bé uma asserção de largura zero que corresponde se houver \wde um lado e se houver \Wdo outro ou se a posição estiver no início ou no final da string. \wé arbitrariamente definido como caracteres "identificadores" (alnums e sublinhado), não como algo especialmente útil para o inglês.
24510 hobbs
100% correto. Desculpas por não apenas comentar o seu. Apertei enviar antes de ver sua resposta.
Brent escreve código
5
por uma questão de compreensão, é possível reescrever a regex \bhello\bsem usar \b(usando \w, \We outros)?
David Portabella
5
Tipo de :, (^|\W)hello($|\W)exceto que ele não capturaria nenhum caractere que não seja palavra antes e depois, portanto seria mais parecido (^|(?<=\W))hello($|(?=\W))(usando asserções lookahead / lookbehind).
Brianary 28/09/16
6
@brianary um pouco mais simples: (?<!\w)hello(?!\w).
precisa
28

Um limite de palavras pode ocorrer em uma das três posições:

  1. Antes do primeiro caractere na sequência, se o primeiro caractere for um caractere de palavra.
  2. Após o último caractere na sequência, se o último caractere for um caractere de palavra.
  3. Entre dois caracteres na sequência, em que um é um caractere de palavra e o outro não é um caractere de palavra.

Os caracteres do Word são alfanuméricos; um sinal de menos não é. Retirado do Tutorial do Regex .

WolfmanDragon
fonte
21

Durante o aprendizado da expressão regular, fiquei realmente preso ao metacaractere que é \b. Na verdade, não compreendi seu significado enquanto me perguntava " o que é, o que é " repetidamente. Depois de algumas tentativas usando o site , assisto os traços verticais cor-de-rosa no início de todas as palavras e no final das palavras. Entendi bem o significado naquele momento. Agora é exatamente o limite da palavra ( \w) .

Minha opinião é apenas imensamente orientada para a compreensão. A lógica por trás disso deve ser examinada a partir de outras respostas.

insira a descrição da imagem aqui

snr
fonte
3
Um site muito bom para entender o que é um limite de palavra e como partidas estão acontecendo
vsingh
2
Este post merece crédito por mostrar, em vez de dizer. Uma imagem vale mais que mil palavras.
M_M 2/04
13

Um limite de palavra é uma posição que é precedida por um caractere de palavra e não seguida por um, ou seguida por um caractere de palavra e não precedida por um.

Alan Moore
fonte
8

Eu falo sobre quais \blimites de regex estilo estão aqui .

A história curta é que eles são condicionais . O comportamento deles depende do que eles são próximos.

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

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

Às vezes não é isso que você deseja. Veja minha outra resposta para elaboração.

tchrist
fonte
7

Eu gostaria de explicar a resposta de Alan Moore

Um limite de palavras é uma posição que é precedida por um caractere de palavra e não seguida por um ou seguida por um caractere de palavra e não precedida por um.

Suponha que eu tenha uma string "Isso é um c a t, e ela é uma coisa impressionante", e devo substituir todas as ocorrências pela letra 'a' somente se essa letra existir no "Limite de uma palavra" , ou seja, a cartaa dentro de 'gato' não deve ser substituída.

Então, eu vou executar regex (em Python ) como

re.sub("\ba","e", myString.strip())// substitua apore

então a saída será Este é ec um t end ela de ewesome

Daksh Gargas
fonte
5

Corri para um problema ainda pior quando procurar texto para palavras como .NET, C++, C#, eC . Você pensaria que os programadores de computador saberiam melhor do que nomear uma linguagem como algo difícil de escrever expressões regulares.

De qualquer forma, foi o que eu descobri (resumido principalmente em http://www.regular-expressions.info , que é um ótimo site): Na maioria dos tipos de regex, os caracteres correspondentes à classe de caracteres abreviados \wsão os caracteres que são tratados como caracteres de palavra pelos limites da palavra. Java é uma exceção. Java suporta Unicode para \bmas não para \w. (Tenho certeza de que havia uma boa razão para isso no momento).

A \wsignifica "caráter palavra". Sempre corresponde aos caracteres ASCII [A-Za-z0-9_]. Observe a inclusão de sublinhado e dígitos (mas não traço!). Na maioria dos tipos de suporte ao Unicode, \winclui muitos caracteres de outros scripts. Há muita inconsistência sobre quais caracteres estão realmente incluídos. Letras e dígitos de scripts e ideogramas alfabéticos geralmente estão incluídos. A pontuação do conector, exceto os símbolos de sublinhado e numéricos que não são dígitos, pode ou não ser incluída. Esquema XML e XPath incluem até todos os símbolos \w. Mas Java, JavaScript e PCRE correspondem apenas a caracteres ASCII com\w .

É por isso que pesquisas regex Java baseada em para C++, C#ou .NET(mesmo quando você se lembrar de escapar do período e vantagens) são parafusados pelo\b .

Nota: Não tenho certeza do que fazer com relação a erros no texto, como quando alguém não coloca um espaço depois de um ponto no final de uma frase. Eu permiti, mas não tenho certeza de que seja necessariamente a coisa certa a fazer.

De qualquer forma, em Java, se você estiver pesquisando texto para essas linguagens de nomes estranhos, precisará substituir o \bpor antes e depois dos designadores de espaço em branco e pontuação. Por exemplo:

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

Então, em seu teste ou função principal:

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

PS Meus agradecimentos a http://regexpal.com/ sem os quais o mundo regex seria muito infeliz!

Tihamer
fonte
Lutei tentando entender por que eu não podia corresponder C#, mas agora é mais clara
Mugoma J. Okomba
4

Confira a documentação sobre condições de contorno:

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

Confira este exemplo:

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

Ao imprimi-lo, observe que a saída é esta:

[Encontrei o valor -, na minha string.]

Isso significa que o caractere "-" não está sendo escolhido como estando no limite de uma palavra porque não é considerado um caractere de palavra. Parece que @brianary meio que me venceu, então ele recebe uma votação positiva.

Brent escreve código
fonte
2

O limite da palavra \ b é usado onde uma palavra deve ser um caractere de palavra e outra um caractere que não seja palavra. Expressão regular para número negativo deve ser

--?\b\d+\b

verificar DEMO em funcionamento

Anubhav Shakya
fonte
1

Acredito que seu problema se deva ao fato de -não ser um caractere de palavra. Assim, o limite da palavra corresponderá após o- e, portanto, não o capturará. Os limites da palavra correspondem antes dos caracteres da primeira e da última palavra em uma sequência de caracteres, bem como em qualquer lugar em que antes seja um caractere de palavra ou não-palavra e depois o oposto. Observe também que o limite da palavra é uma correspondência de largura zero.

Uma alternativa possível é

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

Isso corresponderá a qualquer número começando com um caractere de espaço e um traço opcional e terminando no limite de uma palavra. Também corresponderá a um número começando no início da string.

Sean
fonte
0

Eu acho que é o limite (ou seja, o caractere a seguir) da última partida ou o começo ou o fim da string.


fonte
1
Você está pensando em \G: corresponde ao início da string (como \A) na primeira tentativa de correspondência; depois disso, corresponde à posição em que a partida anterior terminou.
Alan Moore
0

quando você usa \\b(\\w+)+\\bisso significa correspondência exata com uma palavra que contém apenas caracteres de palavra([a-zA-Z0-9])

no seu caso, por exemplo, a configuração \\bno início do regex aceitará -12(com espaço), mas novamente não aceitará -12(sem espaço)

para referência para apoiar minhas palavras: https://docs.oracle.com/javase/tutorial/essential/regex/bounds.html

vic
fonte