Это третья часть в серии учебных статей регулярных выражений. Это следует за Как это регулярное выражение находит треугольные числа? (где сначала вставляются вложенные ссылки) и Как мы можем сопоставить ^ nb ^ n с регулярным выражением Java?(где детальный механизм подсчета голосов). Эта часть вводит конкретную форму вложенного утверждения, которое в сочетании с вложенными ссылками позволяет регулярному выражению Java соответствовать тому, что большинство людей считают "невозможным": палиндромы!!
Язык палиндромов не является regular; это фактически context-free (для данного алфавита). Тем не менее, современная реализация регулярных выражений распознает больше, чем просто обычные языки, а рекурсивные шаблоны Perl/PCRE и группы балансировки .NET могут легко распознать палиндромы (см.: Вопросы, относящиеся).
Однако механизм Java regex не поддерживает ни одну из этих "расширенных" функций. И все же "кому-то" (* wink *) удалось написать следующее регулярное выражение, которое, похоже, прекрасно выполняет работу (см. Также на ideone.com):
public class Palindrome {
// asserts that the entirety of the string matches the given pattern
static String assertEntirety(String pattern) {
return "(?<=(?=^pattern$).*)".replace("pattern", pattern);
}
public static void main(String[] args) {
final String PALINDROME =
"(?x) | (?:(.) add)+ chk"
.replace("add", assertEntirety(".*? (\\1 \\2?)"))
.replace("chk", assertEntirety("\\2"));
System.out.println(PALINDROME);
// (?x) | (?:(.) (?<=(?=^.*? (\1 \2?)$).*))+ (?<=(?=^\2$).*)
String[] tests = {
"", // true
"x", // true
"xx", // true
"xy", // false
"xyx", // true
"xxx", // true
"xxyx", // false
"racecar", // true
"step on no pets", // true
"aManaPlanaCanalPanaMa", // true
"this is impossible", // FALSE!!!
};
for (String test : tests) {
System.out.printf("[%s] %s%n", test, test.matches(PALINDROME));
}
}
}
Итак, это работает, но как?
Ссылки
-
java.util.regex.Pattern
- regular-expressions.info/Freespacing
(?x)
, Поисковые фразы(?=…)
/(?<=…)
и т.д.
ОБЩИЙ УДОВЛЕТВОРИТЕЛЬНЫЙ ОШИБКА!!!
Это не лучший способ обнаружить палиндромы; это
O(N^3)
в лучшем случае. Выполнение этого обнаружения на более общем языке программирования является более эффективным и более простым.Вы не захотите использовать регулярное выражение для обнаружения палиндромов по тем же причинам, по которым вы не захотите использовать регулярное выражение для нахождения простых чисел. Тем не менее, вы бы изучили, как нерекурсивное неравновесное групповое регулярное выражение может обнаруживать палиндромы по тем же причинам, что и вы изучаете, как регулярное выражение может использоваться для тестирования примитивов: это забавно, это сложно, оно образовательное.
Связанные вопросы
- Как проверить, что строка является палиндром с использованием регулярных выражений? - это "невозможно"! (Если...)
- Как проверить, является ли данная строка палиндромом? - решения без регулярных выражений на многих языках
- Как определить, является ли число простым с регулярным выражением?