Regex не працює в String.matches ()


147

У мене є цей невеликий шматочок коду

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

Передбачається для друку

dkoe

але він нічого не друкує !!


41
Java matchesставить ^ на початку та $ в кінці регулярних виразів для вас. Таким чином matches("[a-z]"), насправді буде шукати / ^ [az] $ / замість цього.
Робіно

Так @Robino ви абсолютно праві.
Міхір

1
Безумовно, якщо ви розраховуєте matchesшукати будь-яке явище [a-z], то воно повинно відповідати всім їм? Я б не сподівався matchesперевірити кожного персонажа окремо проти регулярного вираження.
PhilHibbs

@Robino: Де ця функція описана / задокументована?
Тору

@Toru На сторінці документів Java для String.Matches - де ще? Випадковий Google із документацією "java string match документації" виявляє, у верхньому результаті, фраза "str.matches (regex) дає точно такий же результат, як і вираз". Важливе слово - «точно».
Робіно

Відповіді:


323

Ласкаво просимо до неправильно названого .matches()методу Java ... Він намагається відповідати ВСІМ вхідним даним. На жаль, інші мови наслідували цей приклад :(

Якщо ви хочете перевірити, чи відповідає регулярний вираз вхідному тексту, використовуйте a Pattern, a Matcherта .find()метод відповідника:

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

Якщо ви хочете дійсно побачити, чи вхід містить лише малі літери, ви можете використовувати .matches(), але вам потрібно зіставити один або кілька символів: додайте а +до класу символів, як у [a-z]+. Або використовувати ^[a-z]+$і .find().


2
Я знаходжу в Інтернеті 100-ти неповних навчальних посібників. Не вдалося знайти хорошого. Чи є у вас якісь пропозиції?
Джон

Дякую @fge за пояснення .matches(). Можливо, ви знаєте, чому .find()на цьому прикладі працює так повільно ?
Костянтин Конопко

3
Що ви маєте на увазі під іншими мовами ? Як я знаю, лише C ++ має еквівалентний набір методів - regex_searchі regex_match. У Python re.matchлише закріплюють збіг на початку рядка (як би це було \Apattern), а Python 3.x отримав хороший .fullmatch()метод. У JS, Go, PHP та .NET не існує методів регулярного вирівнювання, які прив'язують збіг неявно. ElasticSearch, XML Schema та HTML5 / Validators Angluar шаблони завжди прив’язані за замовчуванням. У Swift / Objective C є спосіб закріпити шаблон на початку за допомогою параметра.
Wiktor Stribiżew

Чи існує спосіб, який це зробити?
Кардинал -

44

[a-z]відповідає одному знаку між a і z. Так, якби ваша рядок була "d", наприклад, тоді вона збігалася б і була роздрукована.

Потрібно змінити свій регулярний вираз, щоб [a-z]+він відповідав одній або більше знаків.


12
Звичайно, це відповідає одному знаку, ось що робить цей регулярний геть! Однак, не зрозуміло (і не повинно бути так!) - те, що java ставить префікс ^і суфікс $навколо наданого регулярного виразу, змінюючи його небажано і створюючи дивні помилки. Вони не повинні цього робити, тому що саме так малося на увазі початкове повторне вираження.
klaar

28

String.matchesповертає, чи відповідає цілий рядок регулярному вираженню, а не будь-яка підрядка.


3
Щось справді сумна реальність - це те, що ти маєш рацію. Я справді не знаю, чому вони зробили це так.
Hola Soy Edu Feliz Navidad

16

реалізація регулярних виразів java намагається відповідати цілому рядку

це відрізняється від регексів perl, які намагаються знайти відповідну частину

якщо ви хочете знайти рядок, окрім малих символів, використовуйте шаблон [a-z]+

якщо ви хочете знайти рядок, що містить щонайменше один нижній регістр символів, використовуйте шаблон .*[a-z].*


Більше інформації тут
ycomp


12

Б / в

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

4

Я стикався з тією ж проблемою один раз:

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

Сказане не вдалося!

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

Вищезазначене працювало з малюнком в межах (та ).


2

Ваш звичайний вираз [a-z]не відповідає, dkoeоскільки відповідає лише рядкам довжини 1. Використовуйте щось на зразок [a-z]+.


-1

ви повинні розмістити принаймні захоплення ()у шаблоні, щоб відповідати, і виправити такий зразок:

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

Дужки нічого не змінили.
Touniouk

@Touniouk без дужок matchesне має жодного результату.
MohsenB

-3

Ви можете зробити корпус шаблону нечутливим, зробивши:

Pattern p = Pattern.compile("[a-z]+", Pattern.CASE_INSENSITIVE);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.