Я пытаюсь написать правильное регулярное выражение в PHP для анализа строки (написанной некоторым пользователем) для создания запроса. Он может быть таким же сложным, как:
name = 'benjo' and (surname = 'benny' or surname = 'bennie') or age = 4
Позже я проанализирую строку для создания mySQL-запросов. На данный момент я просто пытаюсь найти правильное регулярное выражение для синтаксического анализа этой строки в массив, который может выглядеть так:
$result = array( 0 => name = 'benjo', 1 => and 2 => array( 0 => surname = 'benny', 1 => or, 2 => surname = 'bennie', ), 3 => age = 4 );
Я подумал об использовании рекурсивных функций, и теперь мое регулярное выражение:
"#\((([^()]+|(?R))*)\)|(ou[^()])|(et[^()])#",
который, конечно, не работает.
Я буду рад, если кто-то сможет помочь, я застрял здесь! 🙂 Tks, Romain
ПОЗВОЛЯЙТЕ ПРОБЛЕМ! 🙂 Хорошо, теперь давайте сделаем это немного более простым. Что бы это взяло с регулярным выражением и добавлением ограничения, что мы остаемся на «первом уровне» !! Нет вложенных круглых скобок, только одного уровня, но все равно столько И / ИЛИ … Может ли это что-нибудь изменить или REGEXP? (Я действительно хотел бы избежать написания моего мини-парсера, хотя это звучит действительно интересно …
Теоретическое регулярное выражение недостаточно мощно для сопоставления скобок. Теоретическое регулярное выражение может принимать только правила левой рекурсии / правильной рекурсии. Правила средней рекурсии не могут быть выражены с помощью регулярного выражения (например, <exp> -> "(" <exp> ")"
).
Однако регулярное выражение в языках программирования реализует функции, позволяющие регулярному выражению превосходить возможности регулярной грамматики. Например, backreference в regex позволяет писать регулярное выражение, которое соответствует неконтекстно-свободным языкам . Тем не менее, даже с backreference, по-прежнему невозможно сопоставить круглые скобки с регулярным выражением.
Поскольку библиотека PCRE поддерживает рекурсивное регулярное выражение с помощью функции вызова подпрограммы , технически возможно проанализировать такое выражение с помощью регулярного выражения. Однако, если вы не можете самостоятельно написать регулярное выражение , что означает, что вы понимаете, что вы делаете, и можете изменять регулярное выражение в соответствии с вашими потребностями, вы должны просто написать собственный парсер . В противном случае у вас будет бесполезный беспорядок.
(?(DEFINE) (?<string>'[^']++') (?<int>\b\d+\b) (?<sp>\s*) (?<key>\b\w+\b) (?<value>(?&string)|(?&int)) (?<exp>(?&key) (?&sp) = (?&sp) (?&value)) (?<logic>\b (?:and|or) \b) (?<main> (?<token> \( (?&sp) (?&main) (?&sp) \) | (?&exp) ) (?: (?&sp) (?&logic) (?&sp) (?&token) )* ) ) (?: ^ (?&sp) (?= (?&main) (?&sp) $ ) | (?!^) \G (?&sp) (?&logic) (?&sp) ) (?: \( (?&sp) (?<m_main>(?&main)) (?&sp) \) | (?<m_key>(?&key)) (?&sp) = (?&sp) (?<m_value>(?&value)) )
Демо на regex101
Регулярное выражение выше должно использоваться с preg_match_all
и помещаться между разделителем с флагом x (режим свободного /.../x
): /.../x
.
Для каждого матча:
m_main
захвата m_main
имеет контент, поместите контент через другой раунд сопоставления. m_value
захвата m_key
и m_value
. Блок (?(DEFINE)...)
позволяет вам определять именованные группы захвата для использования в вызовах подпрограмм отдельно от основного шаблона.
(?(DEFINE) (?<string>'[^']++') # String literal (?<int>\b\d+\b) # Integer (?<sp>\s*) # Whitespaces between tokens (?<key>\b\w+\b) # Field name (?<value>(?&string)|(?&int)) # Field value (?<exp>(?&key) (?&sp) = (?&sp) (?&value)) # Simple expression (?<logic>\b (?:and|or) \b) # Logical operators (?<main> # <token> ( <logic> <token> )* # A token can contain a simple expression, or open a parentheses (...) # When we open a parentheses, we recurse into the main pattern again (?<token> \( (?&sp) (?&main) (?&sp) \) | (?&exp) ) (?: (?&sp) (?&logic) (?&sp) (?&token) )* ) )
Остальная часть шаблона основана на этом методе, чтобы соответствовать всем <token>
s в <token> ( <logic> <token> )*
с глобальной операцией согласования.
Последняя часть регулярного выражения, в то время как может быть записана как (?&token)
, расширяется, чтобы соответствовать имени и значению поля в простых выражениях.
(?: \( (?&sp) (?<m_main>(?&main)) (?&sp) \) | (?<m_key>(?&key)) (?&sp) = (?&sp) (?<m_value>(?&value)) )