Как мне перевести это регулярное выражение Perl в Java? - PullRequest
4 голосов
/ 02 сентября 2011

Как бы вы перевели это регулярное выражение Perl в Java?

/pattern/i

Во время компиляции он не соответствует "PattErn" для меня, он терпит неудачу

Pattern p = Pattern.compile("/pattern/i");
Matcher m = p.matcher("PattErn");

System.out.println(m.matches()); // prints "false"

Ответы [ 3 ]

13 голосов
/ 03 сентября 2011

Как бы вы перевели это регулярное выражение Perl на Java?

/pattern/i

Вы не можете.

Есть много причин для этого. Вот некоторые из них:

  • Java не поддерживает столь выразительный язык регулярных выражений, как Perl. В нем отсутствует поддержка графем (например, \X) и полная поддержка свойств (например, \p{Sentence_Break=SContinue}), отсутствуют имена с именами Юникод, нет оператора сброса ветви (?|...|...|), нет именованных групп захвата или логического \x{...} бежать до Java 7, не имеет рекурсивных регулярных выражений и т. д. и т. д. и т. д. Я мог бы написать книгу о том, чего здесь не хватает в Java: привыкнуть возвращаться к очень примитиву и неудобно использовать движок regex по сравнению с к чему ты привык.

  • Еще одна проблема еще хуже, потому что у вас есть похожие faux amis вроде \w и и \b и \s, и даже \p{alpha} и \p{lower}, которые ведут себя по-разному в Java по сравнению с Perl; в некоторых случаях версии Java совершенно непригодны и содержат ошибки. Это потому, что Perl следует UTS # 18 , но до Java 7 Java не делал. Вы должны добавить флаг UNICODE_CHARACTER_CLASSES из Java 7, чтобы они перестали нарушаться. Если вы не можете использовать Java 7, откажитесь сейчас, потому что в Java было много-много других ошибок Unicode до Java 7, и с этим просто не стоит бороться с ними.

  • Java обрабатывает разрывы строк через ^ и $ и ., но Perl ожидает, что разрывы строк в Unicode будут \R. Вы должны посмотреть на UNIX_LINES, чтобы понять, что там происходит.

  • По умолчанию Java не применяет никаких регистров Unicode вообще. Обязательно добавьте флаг UNICODE_CASE к вашей компиляции. В противном случае вы не получите такие вещи, как различные греческие сигмы, совпадающие друг с другом.

  • Наконец, все по-другому, потому что в лучшем случае Java выполняет только простое свертывание, тогда как Perl всегда делает полное сведение. Это означает, что вы не получите \xDF для сопоставления с регистром "SS", нечувствительным к Java, и с аналогичными проблемами.

В итоге, самое близкое, что вы можете получить, это скомпилировать с флагами

 CASE_INSENSITIVE | UNICODE_CASE | UNICODE_CHARACTER_CLASSES

, что эквивалентно встроенному "(?iuU)" в строке шаблона.

И помните, что совпадение в Java не означает совпадение, достаточно извращенно.


EDIT

А вот и остальная часть истории ...

Во время компиляции он не соответствует "PattErn" для меня, он не работает

   Pattern p = Pattern.compile("/pattern/i");
   Matcher m = p.matcher("PattErn");
   System.out.println(m.matches()); // prints "false"

У вас не должно быть косых черт вокруг шаблона.

Лучшее, что вы можете сделать, это перевести

$line = "I have your PaTTerN right here";
if ($line =~ /pattern/i) {
    print "matched.\n";
}

таким образом

import java.util.regex.*;

String line     = "I have your PaTTerN right here";
String pattern  = "pattern";      
Pattern regcomp = Pattern.compile(pattern, CASE_INSENSITIVE
                                        | UNICODE_CASE
                // comment next line out for legacy Java \b\w\s breakage 
                                        | UNICODE_CHARACTER_CLASSES  
                                );    
Matcher regexec = regcomp.matcher(line);    
if (regexec.find()) {
    System.out.println("matched");
} 

Вот, посмотри, насколько это проще? :)

Еще одна вещь, которую вы теряете с Java, потому что Java на самом деле не знает регулярное выражение из двусвязного списка из дыры в его голове, это компиляция шаблонов во время компиляции. Я, я всегда нашел время компиляции лучшим временем для компиляции, но попробуйте рассказать об этом Java. В Java очень сложно осознать эту очень простую меру здравомыслия программы, то, что вам действительно нужно постоянно делать в каждой программе. Этот недостаток дизайна - королевская боль в заднице, потому что в середине вашей программы вы делаете исключение для чего-то, что должно было быть обнаружено во время компиляции, когда остальная часть вашей программы компилировалась. Примерно так же раздражительно, как и прерывание полового акта, потому что вы были на пути к тому, чтобы завершить свой бизнес, и BANG все разрушено.

Я не реализовал решение этой досадной досады в моем коде выше, но вы можете подделать его с некоторой статической инициализацией.

1 голос
/ 02 сентября 2011

Java regex не имеет разделителей и использует отдельный аргумент для изменений:

 Pattern p = Pattern.compile("pattern", Pattern.CASE_INSENSITIVE);
1 голос
/ 02 сентября 2011

Эквивалент Perl:

/pattern/i

в Java будет:

Pattern p = Pattern.compile("(?i)pattern");

Или просто выполните:

System.out.println("PattErn".matches("(?i)pattern"));

Обратите внимание, что "string".matches("pattern") проверяетшаблон против всей строки ввода.Другими словами, следующее будет возвращать false:

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