我相信您正在寻找这样的东西。一路上散布着解释性评论。
如果您要将语法扩展到超出您现有的范围(实际上即使您没有),请编写一个适当的解析器,而不是尝试在单个正则表达式中完成所有操作。这是一个有趣的练习,展示了 PCRE 的一些威力,但它可以very很容易变得难以维护的混乱。
测试字符串:
$tests = [
"a",
"a()",
"a(b)",
"(a?b|c)",
"(a()?(b()?d|e)|(c()?f|g))",
"((h() ? a | i) ? (b() ? d | e) | (c() ? f | g))",
"(a(d(f))?b(e(f))|c)"
];
供以后使用。
Regex:
$regex = <<<'REGEX'
/
(?(DEFINE)
# An expression is any function, ternary, or string.
(?<expression>
(?&function) | (?&ternary) | (?&string)
)
)
^(?<expr>
# A function is a function name (consisting of one or more word characters)
# followed by an opening parenthesis, an optional parameter (expression),
# and a closing parenthesis.
# Optional space is allowed around the parentheses.
(?<function>
(?<func_name> \w+ )
\s*\(\s*
(?<parameter> (?&expression)? )
\s*\)\s*
)
|
# A ternary is an opening parenthesis followed by an 'if' expression,
# a question mark, an expression evaluated when the 'if' is true,
# a pipe, an expression evaluated when the 'if' is false, and a closing
# parenthesis.
# Whitespace is allowed after '('; surrounding '?' and '|'; and before ')'.
(?<ternary>
\(\s*
(?<if> (?&expression) )
\s*\?\s*
(?<true> (?&expression) )
\s*\|\s*
(?<false> (?&expression) )
\s*\)
)
|
# A string, for simplicity's sake here, we'll call a sequence of word
# characters.
(?<string> \w+ )
)$
/x
REGEX;
自由使用命名捕获组有很大帮助,就像x
(PCRE_EXTENDED) 修饰符以允许注释和空格。这(?(DEFINE)...)
块允许您定义仅供参考使用的子模式。
正则表达式演示:
foreach ($tests as $test) {
if (preg_match($regex, $test, $m)) {
echo "expression: $m[expr]\n";
if ($m['function']) {
echo "function: $m[function]\n",
"function name: $m[func_name]\n",
"parameter: $m[parameter]\n";
} elseif ($m['ternary']) {
echo "ternary: $m[ternary]\n",
"if: $m[if]\n",
"true: $m[true]\n",
"false: $m[false]\n";
} else {
echo "string: $m[string]\n";
}
echo "\n";
}
}
Output:
expression: a
string: a
expression: a()
function: a()
function name: a
parameter:
expression: a(b)
function: a(b)
function name: a
parameter: b
expression: (a?b|c)
ternary: (a?b|c)
if: a
true: b
false: c
expression: (a()?(b()?d|e)|(c()?f|g))
ternary: (a()?(b()?d|e)|(c()?f|g))
if: a()
true: (b()?d|e)
false: (c()?f|g)
expression: ((h() ? a | i) ? (b() ? d | e) | (c() ? f | g))
ternary: ((h() ? a | i) ? (b() ? d | e) | (c() ? f | g))
if: (h() ? a | i)
true: (b() ? d | e)
false: (c() ? f | g)
expression: (a(d(f))?b(e(f))|c)
ternary: (a(d(f))?b(e(f))|c)
if: a(d(f))
true: b(e(f))
false: c
有点冗长,但足以很好地展示匹配的内容。
Example compute()
功能:
function compute($expr) {
$regex = '/.../x'; // regex from above
if (!preg_match($regex, $expr, $m)) {
return false;
}
if ($m['function']) {
if ($m['parameter']) {
return $m['func_name'](compute($m['parameter']));
} else {
return $m['func_name']();
}
}
if ($m['ternary']) {
return compute($m['if']) ? compute($m['true']) : compute($m['false']);
}
return $m['string'];
}
非常简单 - 执行匹配的函数,评估匹配的三元表达式,或返回匹配的字符串;在适当的地方递归。
compute()
demo:
function a() {return true;}
function b() {return false;}
function d() {return true;}
function e() {return false;}
function h() {return true;}
foreach ($tests as $test) {
$result = compute($test);
echo "$test returns: ";
var_dump($result);
}
Output:
a returns: string(1) "a"
a() returns: bool(true)
a(b) returns: bool(true)
(a?b|c) returns: string(1) "b"
(a()?(b()?d|e)|(c()?f|g)) returns: string(1) "e"
((h() ? a | i) ? (b() ? d | e) | (c() ? f | g)) returns: string(1) "e"
(a(d(f))?b(e(f))|c) returns: bool(false)
我很确定这是正确的。