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 строка соответствует документации» показывает, что в верхнем результате фраза «str.matches (regex) дает точно такой же результат, как выражение». Важное слово «точно».
Робино

Ответы:


323

Добро пожаловать в Java по ошибке .matches() метод ... Он пытается и соответствует ВСЕМ входным данным. К сожалению, другие языки последовали примеру :(

Если вы хотите увидеть, соответствует ли регулярное выражение вводимому тексту, используйте a Pattern, a Matcherи .find()метод matcher:

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

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


2
я нахожу сотни неполных уроков онлайн. Не могу найти хороший. Есть ли у вас какие-либо предложения?
Джон

Спасибо @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 есть способ закрепить шаблон в начале с помощью опции.
Виктор Стрибьев

Есть ли единственный способ сделать это?
Кардинал - Восстановить Монику

44

[a-z]соответствует одному символу между a и z. Итак, если бы ваша строка была "d", например, просто , то она бы соответствовала и была распечатана.

Вы должны изменить свое регулярное выражение, [a-z]+чтобы соответствовать одному или нескольким символам.


12
Конечно, это соответствует одному символу, вот что делает это регулярное выражение! Однако, что не ясно (и не должно иметь место!), Это то, что java помещает префикс ^и суффикс $вокруг предоставленного регулярного выражения, изменяя его нежелательно и создавая странные ошибки. Они не должны этого делать, потому что это не то, что подразумевалось под начальным регулярным выражением.
Клар

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.