Regex nie działa w String.matches ()


147

Mam ten mały fragment kodu

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

Powinien drukować

dkoe

ale nic nie drukuje !!


41
Java matchesumieszcza ^ na początku i $ na końcu wyrażeń regularnych. Więc matches("[a-z]")faktycznie szuka zamiast tego / ^ [az] $ /.
Robino

Tak @Robino, masz całkowitą rację.
Mihir

1
Z pewnością, jeśli spodziewasz matchessię szukać jakiegokolwiek wystąpienia [a-z], to powinno pasować do nich wszystkich? Nie spodziewałbym matchessię, że sprawdzę każdą postać indywidualnie w odniesieniu do wyrażenia regularnego.
PhilHibbs

@Robino: Gdzie ta funkcjonalność jest opisana / udokumentowana?
Toru

@Toru Na stronie dokumentacji java dla String.Matches - gdzie jeszcze? Przypadkowe wyrażenie Google „ciąg java pasuje do dokumentacji” ujawnia w górnym wyniku wyrażenie „str.matches (regex) daje dokładnie taki sam wynik jak wyrażenie”. Ważnym słowem jest „dokładnie”.
Robino

Odpowiedzi:


323

Witamy w źle nazwanej .matches()metodzie Javy ... Próbuje i dopasowuje WSZYSTKIE dane wejściowe. Niestety inne języki poszły w jej ślady :(

Jeśli chcesz sprawdzić, czy wyrażenie regularne pasuje do tekstu wejściowego, użyj a Pattern, a Matcheroraz .find()metody dopasowania:

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

Jeśli naprawdę chcesz sprawdzić, czy dane wejściowe mają tylko małe litery, możesz użyć .matches(), ale musisz dopasować jeden lub więcej znaków: dołącz a +do swojej klasy postaci, jak w [a-z]+. Lub użyj ^[a-z]+$i .find().


2
znajduję setki niekompletnych samouczków w Internecie. Nie udało się znaleźć dobrego. Masz jakieś sugestie?
John

Dzięki @fge za wyjaśnienie .matches(). Może wiesz, dlaczego .find()w tym przykładzie działa tak wolno ?
Konstantin Konopko

3
Co masz na myśli mówiąc, że inne języki idą w ich ślady ? Z tego, co wiem, tylko C ++ ma równoważny zestaw metod - regex_searchi regex_match. W Pythonie re.matchtylko zakotwicza dopasowanie na początku łańcucha (tak jakby było \Apattern), a Python 3.x ma fajną .fullmatch()metodę. W JS, Go, PHP i .NET nie ma metod regex, które niejawnie zakotwiczają dopasowanie. ElasticSearch, XML Schema i HTML5 / Validators Wzorce angluar są zawsze domyślnie zakotwiczone. W Swift / Objective C istnieje sposób na zakotwiczenie wzoru na początku za pomocą opcji.
Wiktor Stribiżew

Czy jest na to sposób oneliner?
Kardynał - Przywróć Monikę

44

[a-z]dopasowuje pojedynczy znak od a do z. Tak więc, jeśli twój ciąg "d"byłby na przykład tylko, to zostałby dopasowany i wydrukowany.

Musisz zmienić swoje wyrażenie regularne na, [a-z]+aby dopasować jeden lub więcej znaków.


12
Oczywiście pasuje do pojedynczego znaku, to właśnie robi to wyrażenie regularne! Nie jest jednak jasne (i nie powinno tak być!) To fakt, że java umieszcza przedrostek ^i sufiks $wokół podanego wyrażenia regularnego, zmieniając je niechcianie i tworząc dziwne błędy. Nie powinni tego robić, ponieważ nie tak rozumiano pierwotne wyrażenie regularne.
klaar

28

String.matcheszwraca, czy cały ciąg pasuje do wyrażenia regularnego, a nie tylko do dowolnego podłańcucha.


3
Coś, co jest naprawdę smutną rzeczywistością, to fakt, że masz rację. Naprawdę nie wiem, dlaczego zrobili to w ten sposób.
Hola Soy Edu Feliz Navidad

16

implementacja wyrażeń regularnych w języku java próbuje dopasować cały ciąg

różni się od wyrażeń regularnych perla, które próbują znaleźć pasującą część

jeśli chcesz znaleźć ciąg zawierający tylko małe litery, użyj wzorca [a-z]+

jeśli chcesz znaleźć ciąg zawierający co najmniej jedną małą literę, użyj wzorca .*[a-z].*


więcej informacji tutaj
ycomp

3
Dlaczego nie jest to udokumentowane ?
Leo Orientis

12

Używany

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

4

Kiedyś napotkałem ten sam problem:

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

Powyższe zawiodło!

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

Powyższe działało ze wzorem w obrębie (i ).


2

Twoje wyrażenie regularne [a-z]nie pasuje, dkoeponieważ pasuje tylko do Ciągów o długości 1. Użyj czegoś w rodzaju [a-z]+.


-1

musisz umieścić co najmniej przechwycenie ()we wzorcu, aby dopasować i poprawić wzór w następujący sposób:

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

Wsporniki niczego nie zmieniły.
Touniouk

@Touniouk bez nawiasów matchesnie ma żadnego wyjścia.
MohsenB

-3

Aby wzorzec nie uwzględniał wielkości liter, wykonaj:

Pattern p = Pattern.compile("[a-z]+", Pattern.CASE_INSENSITIVE);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.