【问题标题】:Numbered occurrences for preg_replace_callbackpreg_replace_callback 的编号出现次数
【发布时间】:2017-04-25 05:31:09
【问题描述】:

我试图弄清楚如何识别匹配的正则表达式组的出现顺序。但找不到任何此类功能。然而,我确信它必须在那里,我只是做错了什么......

到目前为止,我有这个:

$string = "SELECT id, title FROM table WHERE id = ?d AND qwe=?s";
$pattern = '/(\?+[sdf]{1})/i';
$data = array(111, 222, 333);
$inc = 0;

function callback($matches) {
    global $inc, $data;
    $inc++;

    switch ($matches[0]) {
        case '?s':
            return '`'.$data[$inc].'`';
        case '?d':
            return (int) $data[$inc];
        case '?f':
            return (double) $data[$inc];
    }
}
print_r(preg_replace_callback($pattern, 'callback', $string));

它有效,但是 $inc 的那个东西肯定不是要走的路......

我想在这里完全避免使用 $inc。当这些正则表达式组匹配时,有没有办法知道出现的顺序?这就是我想要做的。所以,也许我不仅会有匹配项,还有一个数字会告诉我这是按顺序排列的匹配项。

这个问题有更好的解决方案吗?

【问题讨论】:

  • 您的代码工作正常吗?我的代码有错误。
  • 是的,它正在工作。我在这里复制代码时忘记了一件事。我现在修好了。你能再试一次吗?
  • 如果我的回答有帮助,也请考虑点赞。

标签: php regex callback


【解决方案1】:

您可以使用closure 代替全局:

$data = array(111, 222, 333);
$inc = 0;
$callback = function ($matches) use (&$data, &$inc) {
  // ...
};
print_r($preg_replace_callback($pattern, $callback, $string);

这不会像global 那样将$inc$data 暴露在更广泛的范围内。

【讨论】:

  • 我想在这里完全避免使用 $inc。当这些正则表达式组匹配时,有没有办法知道出现的顺序?这就是我想要做的。所以,也许我不仅会有匹配项,还有一个数字会告诉我按顺序匹配什么。
  • 啊,那个。我误解了,我认为“$inc 的那个东西”是问题所在的 global 位。
  • 啊,误会了。我会更新我的问题。
  • 不幸的是,不,$inc 位是必需的。 preg_replace_callback 确实有第五个参数“计数:如果指定,此变量将填充完成的替换次数。”,但似乎只是在完成所有替换后才设置。不过,使用闭包比使用全局变量要好。
  • 嗯...当组匹配时,它们可以在正则表达式本身中引用为'$1'等。真的没有办法公开...
【解决方案2】:

您混淆了两件事:多个匹配项和组。当您有组时,您可以访问它们(按名称或按 ID)。当您有多个匹配项时(并且当您使用 preg_replace... 时,您实际上让正则表达式引擎在文本中找到所有不重叠的匹配项并单独处理它们),正则表达式引擎不知道它是否是第一个或第二个,等等。因此,除了使用计数器之外,没有其他方法使用当前输入数据

如果您可以更改输入数据,我建议使用键值对 $data 数组,其中键将等于您要在文本中匹配的变量(s,@ 987654325@,或d)。为了从匹配中访问它们,您需要在您的正则表达式中捕获 [sfd],即您需要用捕获组包装该字符类。

使用

$string = "SELECT id, title FROM table WHERE id = ?d AND qwe=?s";
$pattern = '/\?+([sdf])/i';
$data = array("s" => 111, "d" => 222, "f" => 333);
$inc = 0;

echo preg_replace_callback($pattern, function ($matches) use ($data) {
    switch ($matches[0]) {
        case '?s':
            return '`'.$data[$matches[1]].'`';
        case '?d':
            return (int) $data[$matches[1]];
        case '?f':
            return (double) $data[$matches[1]];
    }
}, $string);

请参阅PHP demo

【讨论】:

    【解决方案3】:

    你使用的方法完全没问题,但是如果你想改变你可以使用这个。

    Try this code snippet here

    <?php
    ini_set('display_errors', 1);
    $string = "SELECT id, title FROM table WHERE id = ?d AND qwe=?s";
    $data = array(111, 222, 333);
    $pattern = '/(?:\?+[sdf])/i';
    $counter=0;
    
    while(preg_match($pattern, $string,$matches,PREG_OFFSET_CAPTURE))
    {
        switch ($matches[0][0]) 
        {
            case '?s':
                $replacement= '`'.$data[$counter].'`';
                break;
            case '?d':
                $replacement= (int) $data[$counter];
                break;
            case '?f':
                $replacement= (double) $data[$counter];
                break;
        }
        $string=substr_replace($string,$replacement,$matches[0][1], strlen($matches[0][0]));
        $counter++;
    }
    echo $string;
    

    【讨论】:

      猜你喜欢
      • 2010-11-18
      • 1970-01-01
      • 1970-01-01
      • 2021-09-29
      • 1970-01-01
      • 2021-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多