Regex não funciona em String.matches ()

147

Eu tenho esse pequeno pedaço de código

String[] words = {"{apf","hum_","dkoe","12f"};
for(String s:words)
{
    if(s.matches("[a-z]"))
    {
        System.out.println(s);
    }
}

Deveria imprimir

dkoe

mas não imprime nada !!

John
fonte
41
O Java matchescoloca um ^ no início e um $ no final das regexes para você. Então matches("[a-z]"), na verdade, procurará / ^ [az] $ /.
Robino 2/08/16
Sim, Robino, você está absolutamente certo.
Mihir
1
Certamente, se você espera matchesprocurar alguma ocorrência de [a-z], deve corresponder a todas elas? Eu não esperaria matchesverificar cada personagem individualmente em relação ao regex.
21418 PhilHibbs às
@Robino: Onde essa funcionalidade é descrita / documentada?
Toru
@ Toru Na página java docs para String.Matches - onde mais? Um Google casual de "java string corresponde à documentação" revela, no resultado principal, a frase "str.matches (regex) produz exatamente o mesmo resultado que a expressão". A palavra importante é "exatamente".
Robino 04/04

Respostas:

323

Bem-vindo ao .matches()método errado de Java ... Ele tenta e corresponde a TODA a entrada. Infelizmente, outros idiomas seguiram o exemplo :(

Se você deseja ver se o regex corresponde a um texto de entrada, use a Pattern, a Matchere o .find()método do correspondente:

Pattern p = Pattern.compile("[a-z]");
Matcher m = p.matcher(inputstring);
if (m.find())
    // match

Se o que você deseja é realmente ver se uma entrada possui apenas letras minúsculas, você pode usá-lo .matches(), mas precisa corresponder a um ou mais caracteres: acrescente a +à sua classe de caracteres, como em [a-z]+. Ou use ^[a-z]+$e .find().

fge
fonte
2
Acho centenas de tutoriais incompletos online. Não foi possível encontrar uma boa. Você tem alguma sugestão?
John
Thanx @fge para explicar .matches(). Pode ser que você saiba por que .find()funciona tão devagar neste exemplo ?
Konstantin Konopko
3
O que você quer dizer com outras línguas seguiu o exemplo ? Pelo que sei, apenas C ++ tem um conjunto equivalente de métodos - regex_searche regex_match. No Python, re.matchapenas ancora a correspondência no início da string (como se fosse \Apattern) e o Python 3.x possui um bom .fullmatch()método. Em JS, Go, PHP e .NET, não há métodos regex que ancoram a correspondência implicitamente. Os padrões ElasticSearch, XML Schema e HTML5 / Validators Angluar são sempre ancorados por padrão. No Swift / Objective C, há uma maneira de ancorar o padrão no início com uma opção.
Wiktor Stribiżew
Existe uma maneira oneliner de fazer isso?
Cardinal - Restabelece Monica
44

[a-z]corresponde a um único caractere entre a e z. Portanto, se sua string fosse justa "d", por exemplo, ela seria compatível e impressa.

Você precisa alterar seu regex [a-z]+para corresponder a um ou mais caracteres.

dogbane
fonte
12
É claro que corresponde a um único caractere, é o que o regexp faz! O que não está claro no entanto (e também não deve ser o caso!) É que o java coloca o prefixo ^e o sufixo em $torno do regexp fornecido, alterando-o indesejadamente e criando bugs estranhos. Eles não devem fazer isso, porque não é assim que o regexp inicial foi criado.
Klaar
28

String.matchesretorna se a sequência inteira corresponde ao regex, não apenas a qualquer substring.

yshavit
fonte
3
Algo que é realmente uma triste realidade é que você está certo. Eu realmente não sei por que eles fizeram dessa maneira.
Hola Soy Edu Feliz Navidad
16

A implementação de regex do Java tenta corresponder a toda a cadeia

diferente das expressões regulares perl, que tentam encontrar uma parte correspondente

se você deseja encontrar uma string com apenas caracteres minúsculos, use o padrão [a-z]+

se você deseja encontrar uma sequência contendo pelo menos um caractere minúsculo, use o padrão .*[a-z].*

Hachi
fonte
mais informações aqui
ycomp 12/03
3
Por que isso não está documentado ?!
Leo Orientis 22/06
12

Usava

String[] words = {"{apf","hum_","dkoe","12f"};
    for(String s:words)
    {
        if(s.matches("[a-z]+"))
        {
            System.out.println(s);
        }
    }
Boni
fonte
4

Já enfrentei o mesmo problema uma vez:

Pattern ptr = Pattern.compile("^[a-zA-Z][\\']?[a-zA-Z\\s]+$");

O acima falhou!

Pattern ptr = Pattern.compile("(^[a-zA-Z][\\']?[a-zA-Z\\s]+$)");

O acima trabalhou com padrão dentro (e ).

Shanta
fonte
2

Sua expressão regular [a-z]não corresponde, dkoepois corresponde apenas a seqüências de comprimento 1. Use algo como [a-z]+.


fonte
-1

você deve colocar pelo menos uma captura ()no padrão para corresponder e corrigir o padrão assim:

String[] words = {"{apf","hum_","dkoe","12f"};
for(String s:words)
{
    if(s.matches("(^[a-z]+$)"))
    {
        System.out.println(s);
    }
}
MohsenB
fonte
Suportes não mudaram nada.
Touniouk
@Touniouk sem suportes matchesnão tem saída.
MohsenB 23/02/19
-3

Você pode tornar seu padrão sem distinção de maiúsculas e minúsculas fazendo:

Pattern p = Pattern.compile("[a-z]+", Pattern.CASE_INSENSITIVE);
Anita Kulkarni
fonte