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


How to find a string match within a subject for this pattern {{ @sql( query ) }}

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

我的字符串包含类似这样的东西

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

我需要返回以下数据

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

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

$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

您无法使用 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 演示

编辑:

来自官方 PHP 文档:

重复捕获子

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

括号是特殊字符。所以如果你想要文字括号,你应该转义它们

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

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

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