java.util.regex - важность Pattern.compile ()? - PullRequest
108 голосов
/ 12 ноября 2009

В чем важность метода Pattern.compile()?
Зачем мне нужно скомпилировать строку регулярного выражения перед получением объекта Matcher?

Например:

String regex = "((\\S+)\\s*some\\s*";

Pattern pattern = Pattern.compile(regex); // why do I need to compile
Matcher matcher = pattern.matcher(text);

Ответы [ 7 ]

135 голосов
/ 12 ноября 2009

Метод compile() всегда вызывается в какой-то момент; это единственный способ создать объект Pattern. Таким образом, вопрос в том, почему вы должны называть это явно ? Одна из причин заключается в том, что вам нужна ссылка на объект Matcher, чтобы вы могли использовать его методы, например group(int), для извлечения содержимого групп захвата. Единственный способ получить объект Matcher - метод matcher() объекта Pattern, а единственный способ получить объект Pattern - метод compile(). Тогда есть метод find(), который, в отличие от matches(), не дублируется в классах String или Pattern.

Другая причина - избегать создания одного и того же объекта Pattern снова и снова. Каждый раз, когда вы используете один из методов на основе регулярных выражений в String (или статический метод matches() в Pattern), он создает новый Pattern и новый Matcher. Итак, этот фрагмент кода:

for (String s : myStringList) {
    if ( s.matches("\\d+") ) {
        doSomething();
    }
}

... в точности соответствует этому:

for (String s : myStringList) {
    if ( Pattern.compile("\\d+").matcher(s).matches() ) {
        doSomething();
    }
}

Очевидно, это делает много ненужной работы. Фактически, для компиляции регулярного выражения и создания экземпляра объекта Pattern может потребоваться больше времени, чем для фактического сопоставления. Поэтому обычно имеет смысл вытащить этот шаг из цикла. Вы также можете создать Matcher заранее, хотя они и не такие дорогие:

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("");
for (String s : myStringList) {
    if ( m.reset(s).matches() ) {
        doSomething();
    }
}

Если вы знакомы с регулярными выражениями .NET, вам может быть интересно, связан ли метод Java compile() с модификатором .NET RegexOptions.Compiled; ответ - нет. Java Pattern.compile() метод просто эквивалентен конструктору Regex .NET. При указании опции Compiled:

Regex r = new Regex(@"\d+", RegexOptions.Compiled); 

... он компилирует регулярное выражение непосредственно в байт-код CIL, что позволяет ему работать намного быстрее, но при значительных затратах на предварительную обработку и использование памяти - считайте его стероидами для регулярных выражений. Java не имеет аналогов; нет никакой разницы между шаблоном, который создается за сценой с помощью String#matches(String), и шаблоном, который вы создаете явно с помощью Pattern#compile(String).

(EDIT: я изначально говорил, что все объекты .NET Regex кэшируются, что неверно. Начиная с .NET 2.0 автоматическое кэширование происходит только со статическими методами, такими как Regex.Matches(), а не при непосредственном вызове конструктора Regex. ссылка )

35 голосов
/ 12 ноября 2009

Компиляция анализирует регулярное выражение и создает представление в памяти . Затраты на компиляцию значительны по сравнению с соответствием. Если вы используете шаблон несколько раз , это увеличит производительность при кэшировании скомпилированного шаблона.

17 голосов
/ 12 ноября 2009

Когда вы компилируете Pattern, Java выполняет некоторые вычисления, чтобы ускорить поиск совпадений за String с. (Создает представление регулярного выражения в памяти)

Если вы собираетесь многократно использовать Pattern, вы увидите значительное увеличение производительности по сравнению с созданием нового Pattern каждый раз.

В случае использования Pattern только один раз, шаг компиляции выглядит как дополнительная строка кода, но на самом деле он может быть очень полезен в общем случае.

5 голосов
/ 13 июня 2015

Это вопрос производительности и использования памяти, скомпилируйте и сохраните соответствующий шаблон, если вам нужно его много использовать. Типичное использование регулярных выражений заключается в проверке пользовательских входных (формат) , а также форматных выходных данных для пользователей , в этих классах сохранение сохраненного шаблона выглядит вполне логичным, как они обычно называют много.

Ниже приведен пример валидатора, который на самом деле называется много :)

public class AmountValidator {
    //Accept 123 - 123,456 - 123,345.34
    private static final String AMOUNT_REGEX="\\d{1,3}(,\\d{3})*(\\.\\d{1,4})?|\\.\\d{1,4}";
    //Compile and save the pattern  
    private static final Pattern AMOUNT_PATTERN = Pattern.compile(AMOUNT_REGEX);


    public boolean validate(String amount){

         if (!AMOUNT_PATTERN.matcher(amount).matches()) {
            return false;
         }    
        return true;
    }    
}

Как упомянул @Alan Moore, если в вашем коде есть многоразовое регулярное выражение (например, перед циклом), вы должны скомпилировать и сохранить шаблон для повторного использования.

0 голосов
/ 18 сентября 2018

Класс Pattern является точкой входа в механизм регулярных выражений. Вы можете использовать его через Pattern.matches () и Pattern.comiple (). Разница между этими двумя. match () - для быстрой проверки соответствия текста (String) заданному регулярному выражению comiple () - создать ссылку на шаблон. Поэтому можно использовать несколько раз, чтобы сопоставить регулярное выражение с несколькими текстами.

Для справки:

public static void main(String[] args) {
     //single time uses
     String text="The Moon is far away from the Earth";
     String pattern = ".*is.*";
     boolean matches=Pattern.matches(pattern,text);
     System.out.println("Matches::"+matches);

    //multiple time uses
     Pattern p= Pattern.compile("ab");
     Matcher  m=p.matcher("abaaaba");
     while(m.find()) {
         System.out.println(m.start()+ " ");
     }
}
0 голосов
/ 27 апреля 2018

Как и в «Pattern.compile», есть «RECompiler.compile» [из com.sun.org.apache.regexp.internal], где:
1. скомпилированный код для pattern [a-z] содержит в себе 'az'
2. скомпилированный код для шаблона [0-9] содержит «09»
3. скомпилированный код для шаблона [abc] содержит aabbcc.

Таким образом, скомпилированный код - отличный способ обобщить несколько случаев. Таким образом, вместо того, чтобы иметь разные ситуации обработки кода 1,2 и 3. Проблема сводится к сравнению с ascii текущего и следующего элемента в скомпилированном коде, отсюда и пары. таким образом
а. что-нибудь с ASCII между A и Z находится между A и Z
б. что-нибудь с ascii между 'a и a определенно' a '

0 голосов
/ 12 ноября 2009

Предварительная компиляция регулярного выражения увеличивает скорость. Повторное использование Matcher дает вам еще одно небольшое ускорение. Если метод вызывается часто, скажем, вызывается в цикле, общая производительность, безусловно, возрастет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...