Regex表达式以拆分混合表达式的混合



我正试图将以下表达式拆分为每个数组,这样我就可以使用分流码算法将其转换为后缀并在稍后进行评估。这是绳子的一部分。

$string = '(fld_1010=="t" or fld_1010 != "test") and fld_1012 >= "18"

我正在使用以下模式

$pattern = "/([(|s]*)(fld_)([0-9]*)[s]*(!=|==|>=|<=|=|>|<|like|in)(.*?)([)|s]*)( and| or|z)/";
$found preg_match_all($pattern , $string , $result,PREG_SET_ORDER);
print_r($result);

但我得到了这个输出:

[
[
"(fld_1010=="t" or",
"(",
"fld_",
"1010",
"==",
""t"",
"",
" or"
],
[
" fld_1010 != "test") and",
" ",
"fld_",
"1010",
"!=",
" "test"",
")",
" and"
],
[
" fld_1012 >= "18"",
" ",
"fld_",
"1012",
">=",
" "18"",
"",
""
]
]

我怎么能像这样把绳子劈开?

[
"(",
"fld_1010",
"==",
"t",
"or",
"fld_1010",
"!=",
"test",
")",
"and",
"fld_1012",
">=",
"18"
]

我正在关注这个链接,但它只适用于带有数字的数学表达式。

谢谢。

您应该分阶段解决这个问题。第一阶段确实是对输入进行标记化,但不应尝试使用此步骤来验证标记的顺序是否有效。只关注单个令牌语法,而不关注出现这些令牌的上下文。所以现在不要检查括号是否平衡,或者运算符是否出现在两个操作数之间。。。等

另一件需要更改的事情是传递给preg_match_all的最后一个参数:使用PREG_PATTERN_ORDER。这样,您就可以在一个子阵列中获得所有匹配,并且所有潜在的捕获组都将收集在单独的子阵列中。

我会保留一个捕捉组来捕捉任何不符合任何模式的东西。这将是语法错误的指示。

以下是如何做到这一点:

$string = '(fld_1010=="t" or fld_1010 != "test") and fld_1012 >= "18"';
// This pattern does not verify any order; just the valid tokens.
// The final (S+) is a "catchall" for errors:
$pattern = '/[!=<>]=|[<>()]|b(?:like|in|and|or|fld_[0-9]*)b|"[^"]*"|(S+)/';
// Use PREG_PATTERN_ORDER here
$found = preg_match_all($pattern , $string , $result, PREG_PATTERN_ORDER);
// Extract the second subarray, as it will have the matches with (S+):
$errors = array_filter($result[1]);
if ($errors) {
echo "following tokens are invalid:n";
print_r($errors);
}
$result = $result[0]; // just get the matches
print_r($result); // This outputs what you were looking for.

注意,对于字符串文字,我没有做任何事情来允许双引号成为其中的一部分(带有一些转义符(。如果您需要这个,您将需要扩展正则表达式来处理它。

第二个阶段将验证这些令牌是否按有效顺序出现。我不会尝试使用正则表达式,而是使用PHP代码。表达式可能会变得非常复杂,有很多嵌套的括号,潜在的函数调用(比如"abs(("(,一元运算符(如"+"或"not"(和二元运算符、优先级规则(如加法前的乘法(、结合性规则(如从右到左的幂运算(。。。等

另一个实现

作为参考,我想指出我曾经在JavaScript中做过的一个Shutting Yard实现,其中所有运算符和函数都是动态定义的。也许这对你的目的来说太过分了,但它可能会成为一种灵感。

最新更新