是否可以使用preg_replace
替换所有出现的模式,直到指定的定界符为止?
我想替换一个模式的多次出现,而不是定界符之前的整个字符串。
是否可以在不拆分字符串的情况下一步完成此操作? 是否可以指定在每次替换后将位置指针重置为开始位置?我可以使用前瞻性实现吗?
例如,我想替换以下URL中所有出现的//
,直到?
字符为止。
输入:
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
请注意
//
可能出现零次或多次//
之后发生的?
都不会受到影响。答案 0 :(得分:3)
您可以使用正向前瞻来确保//
后跟?
:
$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:)//(?=.*\?)#', '$1/', $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
答案 1 :(得分:3)
当前接受的答案足以解决问题,但存在一些可能在不久的将来引起问题的问题:
真的在第一次出现?
它仅适用于https
协议(您需要手动添加其他对象以向后看)。
正则表达式:
(^\w+:/|\G[^?/]*)/+
上面的正则表达式调用\G
,它匹配上一个匹配结束的位置。这意味着当找到?
时,它将无法继续匹配。
PHP:
echo preg_replace('@(^\w+:/|\G[^?/]*)/+@', '$1/', $url);
请注意,如果交替的第一面可能无法满足要求,例如,您可能需要在(?!^)
之前先\G
。在://example.com