正则表达式拆分混合表达式
Regex Expression to split mix of mixed expression
我正在尝试将以下表达式拆分到每个数组中,以便我可以使用调车场算法转换为后缀并在稍后进行评估。
这是字符串的一部分。
$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"
]
我正在关注这个link,但它只适用于只有数字的数学表达式。
谢谢。
你应该分阶段解决这个问题。第一阶段确实是将输入标记化,但您不应尝试使用此步骤来验证标记的 order 是否有效。只关注单个标记语法,而不关注这些标记出现的 context。所以先不要检查括号是否平衡,或者运算符是否出现在两个操作数之间,...等等
要更改的另一件事是传递给 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”)和二元运算符、优先规则(例如先乘后加) ,结合性规则(例如从右到左求幂),...等等
另一个实现
仅供参考,我想指出 a Shunting-Yard implementation 我曾经在 JavaScript 中做过,其中所有运算符和函数都是动态定义的。也许这对您的目的来说太过分了,但它可以作为一种灵感。
我正在尝试将以下表达式拆分到每个数组中,以便我可以使用调车场算法转换为后缀并在稍后进行评估。 这是字符串的一部分。
$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"
]
我正在关注这个link,但它只适用于只有数字的数学表达式。
谢谢。
你应该分阶段解决这个问题。第一阶段确实是将输入标记化,但您不应尝试使用此步骤来验证标记的 order 是否有效。只关注单个标记语法,而不关注这些标记出现的 context。所以先不要检查括号是否平衡,或者运算符是否出现在两个操作数之间,...等等
要更改的另一件事是传递给 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”)和二元运算符、优先规则(例如先乘后加) ,结合性规则(例如从右到左求幂),...等等
另一个实现
仅供参考,我想指出 a Shunting-Yard implementation 我曾经在 JavaScript 中做过,其中所有运算符和函数都是动态定义的。也许这对您的目的来说太过分了,但它可以作为一种灵感。