Существует ли необходимость в более декларативном способе выражения регулярных выражений?:)
Я пытаюсь создать функцию Python, которая может принимать простое английское описание регулярного выражения и возвращать регулярное выражение вызывающему.
В настоящее время я думаю об описании в формате YAML.
Таким образом, мы можем сохранить описание в виде исходной строковой переменной, которая передается этой другой функции, и вывод этой функции затем передается модулю "re". Ниже приведен довольно упрощенный пример:
# a(b|c)d+e*
re1 = """
- literal: 'a'
- one_of: 'b,c'
- one_or_more_of: 'd'
- zero_or_more_of: 'e'
"""
myre = re.compile(getRegex(re1))
myre.search(...)
и др.
Кто-нибудь думает, что что-то в этом роде будет более широко использоваться?
Вы знаете уже существующие пакеты, которые могут это сделать?
Каковы ограничения, которые вы видите в этом подходе?
Кто-нибудь думает, имея декларативную строку в коде, сделает ее более удобной для обслуживания?
Ответы
Ответ 1
Для разработчиков, пытающихся писать регулярные выражения, которые легко получить и поддерживать, я задаюсь вопросом, предложит ли такой подход что-либо, что re.VERBOSE
уже не предоставляет.
Для новичков ваша идея может иметь некоторую привлекательность. Тем не менее, прежде чем идти по этому пути, вы можете попытаться высмеять, как будет выглядеть ваш декларативный синтаксис для более сложных регулярных выражений с использованием групп захвата, якорей, утверждений с перспективой и т.д. Одна из проблем заключается в том, что вы можете получить декларативный синтаксис, который так же трудно запомнить как язык регулярного выражения.
Вы также можете подумать об альтернативных способах выражения вещей. Например, первая мысль, которая пришла мне в голову, заключалась в том, чтобы выразить регулярное выражение, используя функции с короткими, легко запоминающимися именами. Например:
from refunc import *
pattern = Compile(
'a',
Capture(
Choices('b', 'c'),
N_of( 'd', 1, Infin() ),
N_of( 'e', 0, Infin() ),
),
Look_ahead('foo'),
)
Но когда я вижу, что в действии это выглядит болью для меня. Есть много аспектов регулярного выражения, которые достаточно интуитивно понятны - например, +
означает "один или несколько". Одним из вариантов был бы гибридный подход, позволяющий вашему пользователю смешивать те части регулярного выражения, которые уже просты с функциями для более эзотерических бит.
pattern = Compile(
'a',
Capture(
'[bc]',
'd+',
'e*',
),
Look_ahead('foo'),
)
Я бы добавил, что, по моему опыту, регулярные выражения касаются изучения процесса мышления. Удобство в синтаксисе - легкая часть.
Ответ 2
Это на самом деле довольно похоже (идентично?) на то, как работает lexer/parser. Если у вас есть определенная грамматика, вы, вероятно, можете написать парсер с не слишком большими проблемами. Например, вы могли бы написать что-то вроде этого:
<expression> :: == <rule> | <rule> <expression> | <rule> " followed by " <expression>
<rule> :: == <val> | <qty> <val>
<qty> :: == "literal" | "one" | "one of" | "one or more of" | "zero or more of"
<val> :: == "a" | "b" | "c" | "d" | ... | "Z" |
Это далеко не идеальное описание. Для получения дополнительной информации просмотрите этот BNF языка регулярных выражений. Затем вы можете посмотреть lexing и parsing выражение.
Если вы сделали это таким образом, вы могли бы немного приблизиться к Natural Language/английским версиям регулярных выражений.
Я вижу, что такой инструмент полезен, но, как было сказано ранее, в основном для начинающих.
Основное ограничение этого подхода будет заключаться в количестве кода, который вы должны написать, чтобы перевести язык в регулярное выражение (и/или наоборот). С другой стороны, я думаю, что инструмент двустороннего перевода на самом деле будет более идеальным и больше использовать. Возможность найти регулярное выражение и превратить его в английский язык может оказаться гораздо более полезным для выявления ошибок.
Конечно, это не займет слишком много времени для регулярного выражения пикапа, поскольку синтаксис обычно является кратким, и большинство значений довольно понятно, по крайней мере, если вы используете | или || как OR
на вашем языке, и вы думаете о * как умножение на 0-N, + как добавление 0-N.
Хотя иногда я бы не прочь набрать "найти один или несколько" а ", за которым следуют три цифры или" b ", а затем" c ""
Ответ 3
Пожалуйста, посмотрите pyparsing. Многие из проблем, которые вы описываете с помощью RE, - это те же самые, которые вдохновили меня написать этот пакет.
Вот некоторые особенности pyparsing из главы e-книги O'Reilly "Что такого особенного в pyparsing?" .
Ответ 4
возможно, не совсем то, о чем вы просите, но есть способ, как писать регулярные выражения более читабельным способом (VERBOSE
, short X
):
rex_name = re.compile("""
[A-Za-z] # first letter
[a-z]+ # the rest
""", re.X)
rex_name.match('Joe')