使用 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
匹配上一个匹配结束的位置。这意味着当找到 ?
时,它不能继续匹配。
PHP:
echo preg_replace('@(^\w+:/|\G[^?/]*)/+@', '/', $url);
请注意,您可能需要 (?!^)
在 \G
之前,如果交替的第一面有可能无法满足,例如在 ://example.com
是否可以使用 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
匹配上一个匹配结束的位置。这意味着当找到 ?
时,它不能继续匹配。
PHP:
echo preg_replace('@(^\w+:/|\G[^?/]*)/+@', '/', $url);
请注意,您可能需要 (?!^)
在 \G
之前,如果交替的第一面有可能无法满足,例如在 ://example.com