结合正则表达式和字符串分析来指定字符串输入验证所需的模式

Combine regex and string analysis to specify a required pattern for string input validation

首先,我应该为我可能是菜鸟的问题道歉,但我只是不知道如何完成相对复杂的任务,作为一个关于正则表达式的新手。我需要的是为字符串输入指定一个验证模式,并对该模式的不同段执行单独的检查。因此,让我们从任务本身开始。我在 laravel 5.4 上使用 php7.0(这应该真的没有任何区别),我需要以某种方式为字符串输入生成匹配模式,该模式如下:

header1: expression1; header2: expression2; header3: expression3 //etc...

我在这里需要的是检查每个 header 是否存在,以及它是否存在于可用 header 的特殊验证列表中。所以我需要提取每个 header.

此外,表达式构建如下

expression1 = (a1 + a2)*(a3-a1)
expression2 = b1*(b2 - b3)/b4
//etc...

重点是每个表达式都包含一些数字参数,这些参数应该构成有效的算术计算。这些参数也应该包含在可用参数占位符的特殊列表中,因此我也需要检查它们。那么,是否有一种简单有效的方法(在纯 php 中使用正则表达式和字符串分析)来指定严格的结构,或者我应该通过分解和 try-catching 逐步完成所有操作?

最佳解决方案是 shorthand 逻辑(或正则表达式?),例如:

$value->match("^n(header: expression)")
->delimitedBy(';')
->where(in_array($header, $allowed_headers))
->where(strtr($expression, array_fill_keys($available_param_placeholders, 0))->isValidArithmeticExpression())

我希望你能遵循我的逻辑。上面的代码将读作:匹配模式 "header: expression" 的 N 次重复,由 ';' 分隔,其中 'header'(假设 $header 是它的值)在一个数组中,其中'expression'(假设 $expression 是它的值)在所有可用参数占位符都已替换为 0 时形成有效的算术表达式。仅此而已。该严格模式的每个偏差都应该 return false。

作为替代方案,我目前正在考虑首先用主要定界符(分号)分解字符串,然后分别分析每个部分。因此,我将必须检查是否存在冒号,然后检查冒号左侧的所有内容是否与有效的 header 名称匹配,以及列右侧的所有内容是否在所有参数时形成有效的算术表达式列表中的名称被随机值替换(例如 0,只是为了检查代码是否执行,我也不知道该怎么做)。无论如何,这种方式似乎有点矫枉过正,我相信应该有一种更流畅的方式来指定所需的模式。

我希望我已经把所有的事情都解释得足够好,如果我解释我的问题有点混乱,我深表歉意。提前感谢每一篇 advice/help!非常感谢!

$test = "header1: (a1 + a2)*(a3-a1); header2: b1*(b2 - b3)/b4; header3: expression3";
$pairs = explode(';', $test);
$headers = [];
$expressions = [];
foreach ($pairs as $p) {
    $he = explode(':', $p);
    $headers[] = trim($he[0]);
    $expressions[] = trim($he[1]);
}
foreach ($headers as $h) {
    if (!in_array($h, $allowed_headers)) {
        return false;
    }
}

foreach ($expressions as $e) {
    preg_match_all('/[a-z0-9]+/', $e, $matches);
    foreach ($matches as $m) {
        if (param_fails($m)) {
            echo "Expression $e contains forbidden param $m.";
        }
    }
}

使用 eval() 必须始终是 Z 计划。根据我对您输入字符串的理解,此方法可以充分验证 headers 和表达式(如果没有,我认为它应该充分清理字符串用于算术解析)。我不使用 Laravel 编写代码,所以如果可以将其转换为 Laravel 语法,我会把这项工作留给你。

代码:(Demo)

$test = "header1: (a1 + a2)*(a3-a1); header2: b1*(b2 - b3)/b4; header3: c1 * (((c2); header4: ((a1 * (a2 - b1))/(a3-a1))+b2";
$allowed_headers=['header1','header3','header4'];

$pairs=explode('; ',$test);
foreach($pairs as $pair){
    list($header,$expression)=explode(': ',$pair,2);
    if(!in_array($header,$allowed_headers)){
        echo "$header is not permitted.";
    }elseif(!preg_match('~^((?:[-+*/ ]+|[a-z]\d+|\((?1)\))*)$~',$expression)){  // based on https://whosebug.com/a/562729/2943403
        echo "Invalid expression @ $header: $expression";
    }else{
        echo "$header passed.";
    }
    echo "\n---\n";
}

输出:

header1 passed.
---
header2 is not permitted.
---
Invalid expression @ header3: c1 * (((c2)
---
header4 passed.
---

我承认上面的模式会匹配 (+ )( +) 所以它不是 breast 最好的模式。因此,也许您的问题可能是使用 eval() 的候选问题。尽管您可能想要 consider/research 一些 github 可以首先 parse/tokenize 算术表达式的创作/插件/解析器。

也许:

任何通过 ifelseif$pair 都可以进入 else 的评估过程。

我会给你一个 headstart/hint 关于一些一般处理的问题,但我会避免给出任何直接指示以避免某些批评者的愤怒。

}else{
    // replace all variables with 0
    //$expression=preg_replace('/[a-z]\d+/','0',$expression);
    // or replace each unique variable with a whole number
    $expression=preg_match_all('/[a-z]\d+/',$expression,$out)?strtr($expression,array_flip($out[0])):$expression;  // variables become incremented whole numbers
    // ... from here use $expression with eval() in a style/intent of your choosing.
    // ... set a battery of try and catch statements to handle unsavory outcomes.
    // https://www.sitepoint.com/a-crash-course-of-changes-to-exception-handling-in-php-7/
}

正则表达式似乎并不像我在发布该问题时想象的那么复杂,因此我已经成功地通过@mickmackusa 的初步领先获得了我自己的完整形式的模式。我最终想出的是,regex101 本身向您解释:https://regex101.com/r/UHMrqL/1 它所基于的逻辑在最初的问题中进行了描述。唯一缺少的是 headers 的值和参数名称的验证,但之后很容易与 preg_match_all 匹配并通过纯 php 检查进行验证。再次感谢您的关注和帮助! :)