Преемник регулярного выражения?
Глядя на некоторые вопросы регулярного выражения, которые обычно задают SO, мне кажется, что существует ряд областей, где традиционный синтаксис regex не соответствует тем задачам, которые люди ищут в настоящее время. Например:
- Я хочу сопоставить число от 1 до 31, как это сделать?
Обычный ответ: не используйте для этого регулярное выражение, используйте обычные условные сравнения. Это хорошо, если у вас есть только номер сам по себе, но не настолько велика, когда вы хотите совместить число как часть более длинной строки. Почему мы не можем написать что-то вроде \d{1~31}
и либо модифицировать регулярное выражение, чтобы выполнить какую-либо форму подсчета, либо заставить механизм регулярного выражения перевести его в [1-9]|[12]\d|3[01]
?
- Как совместить четное/нечетное число вхождений определенной строки?
Это приводит к очень беспорядочному регулярному выражению, было бы здорово иметь возможность делать (mytext){Odd}
.
- Как обработать XML с помощью регулярного выражения?
Мы все знаем, что плохая идея, но эта и подобные задачи были бы проще, если бы оператор [^ ]
не ограничивался только одним символом. Было бы неплохо иметь возможность <name>(.*)[^(</name>)]
- Как проверить письмо с регулярным выражением?
Очень часто делается и все же очень сложно делать правильно с регулярным выражением. Это спасло бы всех, кто должен был изобрести колесо, если вместо него мог бы использоваться синтаксис типа {IsEmail}
.
Я уверен, что есть и другие, которые тоже будут полезны. Я не слишком много знаю о внутренностях регулярных выражений, чтобы знать, как легко это будет реализовано, или если это будет возможно. Реализация какой-либо формы подсчета (для решения первых двух проблем) может означать, что это не технически "регулярное выражение", но это было бы полезно.
Является ли синтаксис 'regex 2.0' желательным, технически возможным, и есть ли кто-нибудь, кто работает над чем-то подобным?
Ответы
Ответ 1
Я считаю, что Ларри Стена покрывала это Perl 6 regexes. Основная идея - заменить простые регулярные выражения более полезными правилами грамматики. Их легче читать, и проще вставлять код для таких вещей, как убедиться, что у вас есть несколько совпадений. Кроме того, вы можете назвать такие правила, как IsEmail
. Я не могу перечислить все подробности здесь, но достаточно сказать, это похоже на то, что вы предлагаете.
Вот несколько примеров из http://dev.perl.org/perl6/doc/design/exe/E05.html:
Соответствующий IP-адрес:
token quad { (\d**1..3) <?{ $1 < 256 }> }
$str ~~ m/ <quad> <dot> <quad> <dot> <quad> <dot> <quad> /;
Соответствие вложенных круглых скобок:
$str =~ m/ \( [ <-[()]> + : | <self> ]* \) /;
Аннотированный:
$str =~ m/ <'('> # Match a literal '('
[ # Start a non-capturing group
<-[()]> + # Match a non-paren (repeatedly)
: # ...and never backtrack that match
| # Or
<self> # Recursively match entire pattern
]* # Close group and match repeatedly
<')'> # Match a literal ')'
/;
Ответ 2
Не обвиняйте инструмент, обвините пользователя.
Регулярные выражения были созданы для сопоставления шаблонов в строках. Что это.
Это не было сделано для:
- Проверка целых чисел
- Разбор языка разметки
- Очень сложная проверка (например: RFC 2822)
- Точное сравнение строк
- Орфографическая коррекция
- Векторное вычисление
- Генетическое декодирование
- Чудотворение
- Ребенок
- Управление финансами
- Субатомное разбиение
- Активируется конденсатор потока
- Захват ядра Warp
- Путешествие во времени
- Головная боль, вызывающая
Никогда не думай, что последний. Кажется, что регулярные выражения очень хорошо адаптированы для выполнения этой последней задачи, когда они используются там, где они не должны.
Должны ли мы перепроектировать отвертку, потому что она не может гвоздь? НЕТ, используйте молоток.
Просто используйте подходящий инструмент для задачи. Прекратите использование регулярных выражений для задач, для которых они не подходят.
-
Я хочу сопоставить число от 1 до 31, как это сделать?
Используйте свои языковые конструкции, чтобы попытаться преобразовать строку в целое число и выполнить соответствующие сравнения.
-
Как совместить четное/нечетное число вхождений определенной строки?
Регулярные выражения не являются синтаксическим анализатором строк. Тем не менее, вы можете извлечь соответствующую часть с регулярным выражением, если вам нужно только проанализировать подстроку исходной строки.
-
Как обработать XML с помощью регулярного выражения?
Вы этого не сделаете. Используйте XML или HTML-парсер в зависимости от ваших потребностей. Кроме того, синтаксический анализатор XML не может выполнять работу с парсером HTML (если только у вас нет полностью сформированного документа XHTML), и обратное также верно.
-
Как проверить письмо с регулярным выражением?
Вы либо используете эту большую мерзость, либо делаете это правильно с парсером.
Ответ 3
Возможно, это уже есть и с давних времен. Он назывался "грамматики". Вы когда-нибудь слышали о yacc и lex? Теперь нужно что-то простое. Как это ни странно, большая сила регулярного выражения заключается в том, что их очень просто написать на месте.
Я верю, что в некоторых (но крупных) специализированных областях уже есть что нужно. Я думаю о синтаксисе XPath.
Существует ли более широкая (не ограниченная XML, но все еще простая) альтернатива, которая может охватывать все случаи? Возможно, вам стоит взглянуть на perl 6 grammars.
Ответ 4
Все это возможно в Perl.
Чтобы соответствовать 1..31 с шаблоном регулярного выражения:
/( [0-9]+ ) (?(?{ $^N < 1 && $^N > 31 })(*FAIL)) /x
Чтобы создать нечто вроде [1-9]|[12]\d|3[01]
:
use Regexp::Assemble qw( );
my $ra = Regexp::Assemble->new();
$ra->add($_) for (1..31);
my $re = $ra->re; # qr/(?:[456789]|3[01]?|1\d?|2\d?)/
Perl 5.10+ использует попытки оптимизации чередования, поэтому должно быть достаточно:
my $re = join '|', 1..31;
$re = qr/$re/;
Чтобы соответствовать четному количеству вхождений:
/ (?: pat{2} )* /x
Чтобы соответствовать нечетному количеству вхождений:
/ pat (?: pat{2} )* /x
Отрицательное соответствие шаблона:
/<name> (.*?) </name>/x # Non-greedy matching
/<name> ( (?: (?!</name>). )* ) </name>/x
Чтобы получить шаблон, соответствующий адресам электронной почты:
use Regexp::Common qw( Email::Address );
/$RE{Email}{Address}/
Ответ 5
Нет. Мы должны оставить регулярные выражения как есть. Они уже слишком сложны. Когда в последний раз вы думали, что вы прибили его, т.е. Получили полный расширенный синтаксис регулярного выражения (выберите свой вкус), загруженный в вашу сквошную память?
Теория регулярных выражений проста и проста. Но тогда мы хотели, чтобы это и было с ним. Инструмент полезен, но не подходит для нерегулярного сопоставления. Это нормально!
То, что большинство людей пропускает, заключается в том, что контекстно-свободные грамматики и небольшие специализированные интерпретаторы действительно легко писать.
Вместо того, чтобы делать регулярные выражения сложнее, мы должны укрепить поддержку парсера в стандартных библиотеках для наших языков выбора!