使用 preg_replace 重置位置指针以替换所有出现的模式,直到单步分隔符

Reset position pointer to replace all occurrences of a pattern until delimiter in single step using preg_replace

是否可以使用 preg_replace 替换所有出现的模式,直到指定的分隔符?

我想替换多次出现的模式,而不是分隔符之前的整个字符串。

是否可以在不拆分字符串的情况下一步完成? 是否可以指定每次替换后将位置指针重置为开头?我可以使用前瞻来实现这一目标吗?

例如,我想替换以下网址中出现的所有 //,直到 ? 字符。

输入:

https://www.example.com//abc/def/ghi/?jkl=mno//pqr
https://www.example.com//abc/def//ghi/?jkl=mno//pqr
https://www.example.com//abc//def//ghi/?jkl=mno//pqr

预期输出:

https://www.example.com/abc/def/ghi/?jkl=mno//pqr

请注意

您可以使用正向前瞻来确保 // 后跟 ?:

$urls = array('https://www.example.com//abc/def/ghi/?jkl=mno//pqr',
'https://www.example.com//abc/def//ghi/?jkl=mno//pqr',
'https://www.example.com//abc//def//ghi/?jkl=mno//pqr');
foreach ($urls as $url)
    echo preg_replace('#//(?=.*\?)#', '/', $url) . "\n";

输出:

https:/www.example.com/abc/def/ghi/?jkl=mno//pqr
https:/www.example.com/abc/def/ghi/?jkl=mno//pqr
https:/www.example.com/abc/def/ghi/?jkl=mno//pqr

编辑

正如@revo 指出的那样,这也删除了 https: 之后的 //。为避免这种情况,请添加负面回顾:

foreach ($urls as $url)
    echo preg_replace('#(?<!https:)//(?=.*\?)#', '/', $url) . "\n";

输出:

https://www.example.com/abc/def/ghi/?jkl=mno//pqr
https://www.example.com/abc/def/ghi/?jkl=mno//pqr
https://www.example.com/abc/def/ghi/?jkl=mno//pqr

当前接受的答案足以成为一个解决方案,但存在一些可能在不久的将来导致问题的问题:

  • 真的在到达第一次出现?

  • 后不会立即停止匹配
  • 它只适用于https协议(你需要手动添加其他人来回顾)。

正则表达式:

(^\w+:/|\G[^?/]*)/+

上面的正则表达式调用 \G 匹配上一个匹配结束的位置。这意味着当找到 ? 时,它不能继续匹配。

live demo here

PHP:

echo preg_replace('@(^\w+:/|\G[^?/]*)/+@', '/', $url);

请注意,您可能需要 (?!^)\G 之前,如果交替的第一面有可能无法满足,例如在 ://example.com