我正在尝试在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[^()])#",
当然不起作用。
如果有人可以提供帮助,我会很高兴,我有点被困在这里! :) 韩国社交协会, 罗曼
让我们改变挑战吧! :) 好的,现在让我们更简单一些。使用正则表达式并添加我们保持“一级”的约束需要什么!!没有嵌套的括号,只有一个级别,但仍有尽可能多的AND / OR ...这会改变任何有利于REGEXP的东西吗? (我真的很想避免写我的迷你解析器,虽然听起来很有趣......
答案 0 :(得分:4)
理论正则表达式不足以进行括号匹配。理论正则表达式只能处理左递归/右递归规则。中间递归规则不能用正则表达式表示(例如<exp> -> "(" <exp> ")"
)。
由于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))
)
上面的正则表达式应该与preg_match_all
一起使用,并放在带有x标志的分隔符(自由间距模式)之间:/.../x
。
每场比赛:
m_main
捕获组有内容,请将内容置于另一轮匹配中。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)
)*
)
)
该模式的其余部分为based on this technique,以匹配<token>
中具有全局匹配操作的所有<token> ( <logic> <token> )*
。
正则表达式的最后一部分虽然可以写成(?&token)
,但会扩展为匹配简单表达式中的字段名称和值。
(?:
\( (?&sp) (?<m_main>(?&main)) (?&sp) \)
|
(?<m_key>(?&key)) (?&sp) = (?&sp) (?<m_value>(?&value))
)