如何在此模式的主题中查找字符串匹配{{@sql(query)}}

时间:2016-01-27 23:40:39

标签: php regex preg-match preg-match-all

我正在尝试使用php找到模式匹配。

我的字符串包含类似的内容

{{ @sql( select [name] from [table] where [col1] = 50 AND [col2] = :alt_id_1 AND [col3] = :id  ) }}

我需要返回以下数据

  1. 匹配
  2. 的字符串部分
  3. {{@sql()}
  4. 之间的字符串
  5. 任何以冒号:
  6. 开头的关键字

    例如,如果我有以下字符串

    $subject = 'Hello This is a test. The value found is "{{ @sql( select [name] from [table] where [col1] = 50 AND [col2] = :alt_id_1 AND [col3] = :id  ) }}".';
    

    然后,对于第一个项目符号,我需要返回{{ @sql( select [name] from [table] where [col1] = 50 AND [col2] = :alt_id_1 AND [col3] = :id ) }}

    对于第二个项目符号,我需要返回select [name] from [table] where [col1] = 50 AND [col2] = :alt_id_1 AND [col3] = :id

    对于最后一个项目符号,我将返回一个包含:alt_id_1:id

    的数组

    这是我试过的

    $pattern = '/\{\{\s*+@sql(*)+\s*+\}\}/i';
    $matches = [];
    preg_match_all($pattern, $subject, $matches, PREG_OFFSET_CAPTURE);
    echo '<pre>';
    print_r($matches );
    echo '</pre>';
    

    但它给了我一个例外

    preg_match_all(): Compilation failed: nothing to repeat at offset 13
    

2 个答案:

答案 0 :(得分:1)

括号是特殊字符。因此,如果你想要文字括号,你应该逃避它们

$pattern = '/\{\{\s*+@sql\([^\)]*\)\s*+\}\}/i';

(*)+更改为\([^\)]*\)

编译错误来自)+,因为它无法将)识别为转发器的有效字符(+)。

答案 1 :(得分:1)

您无法使用PREG和大多数其他正则表达式语法捕获重复的子模式

所以,你可以试试这个:

$pattern = '/\{\{\s*+@sql\((.+(\:[^ ]+))+.*\)+\s*+\}\}/i';

preg_match_all将捕获最后一个子模式。 如果您事先知道所有主题将具有完全相同数量的:xxx子串,则可以通过以下方式设置模式:

$pattern = '/\{\{\s*+@sql\((.+(\:[^ ]+).+(\:[^ ]+).*)\)+\s*+\}\}/i';

否则,您必须运行两个不同的preg_match

$pattern1 = '/\{\{\s*+@sql\((.+)\)+\s*+\}\}/i';
$pattern2 = '/:[^ ]+/i';

preg_match    ( $pattern1, $subject,       $matches,   PREG_OFFSET_CAPTURE );
preg_match_all( $pattern2, $matches[1][0], $repeating, PREG_OFFSET_CAPTURE );

eval.in demo

编辑:

来自官方PHP Documentation

  

当重复捕获子模式时,捕获的值是与最终迭代匹配的子字符串