如何替换字符串中除第一个字符之外的字符的出现

How to replace occurence of a character in a string except the first one

我想做的是在字符串中找到问号并将其替换为 & 除了第一个。到目前为止我的代码:

$str = 'www.domain.com?adult=2&airport=40-48?destination=recko';        
    echo preg_replace(array('/[?]/'), '&', $str );

输出:

www.domain.com&adult=2&airport=40-48&destination=recko

如何忽略第一次出现的 ?

将字符串的开头匹配到第一个 ? 并使用 (*SKIP)(*F) 省略第一个匹配项:

$str = 'www.domain.com?adult=2&airport=40-48?destination=recko';        
echo preg_replace('/^[^?]*\?(*SKIP)(*F)|[?]/', '&', $str );
// => www.domain.com?adult=2&airport=40-48&destination=recko

IDEONE demo

图案详情:

  • ^ - 字符串的开头
  • [^?]* - 除了?之外的0+字符尽可能多
  • \? - 文字 ?
  • (*SKIP)(*F) - 两个 PCRE 动词使正则表达式引擎在当前迭代中忽略到目前为止匹配的文本
  • | - 或
  • [?] - 文字 ?

(*SKIP)(*FAIL) 的替代方法是使用 preg_replace_callback 和前一种模式,第一个替代分支位于捕获括号内 :

$str = 'www.domain.com?adult=2&airport=40-48?destination=recko';        
echo preg_replace_callback('/^([^?]*[?])|[?]/', function($m) {
    return !empty($m[1]) ? $m[1] : "&";
}, $str );

this IDEONE demo

^([^?]*[?]) 部分从头开始匹配字符串部分将第一个 ? 并放入第 1 组。在我们传递匹配对象的匿名方法中 ($m) ,我们可以在 !empty($m[1]) 的帮助下检查组是否匹配 ("participated in the match")。如果是,我们就把它放回去。如果不匹配,[?],第二个分支匹配,所以,我们替换它。

不知道这是否是最干净的方法,但可以工作并且很简单:

echo substr($str,0,1) . preg_replace(array('/[?]/'), '&', substr($str,1));

我们只是循环思考整个字符串以找到第一个?并用 & 替换彼此。无需使用速度缓慢的正则表达式

<?php
$str = 'www.domain.com?adult=2&airport=40-48?destination=recko';     

$strlen = strlen($str);
$passed_first = false;

for($i = 0; $i < $strlen; $i++) {
    if($str[$i] == "?") {
        if(!$passed_first) {
            $passed_first = true;
        } else {
            $str[$i] = "&"; 
        }
    }
}

echo $str;

我认为最好的方法是做 explode("?",$str)explode("&",$str) 并将它们放入一个数组中,然后用小的 if 条件做 preg_replace() 你取第一个 ? 剩下的你忽略并做 array_marge().

试试看然后告诉我

请参阅有关 parse_url

的文档

有了它,您可以轻松地提取部分 url 并仅在您感兴趣的组件上进行字符串替换

<?php

$str = 'www.domain.com?adult=2&airport=40-48?destination=recko';

$url = parse_url($str);
$url['query'] = str_replace('?', '&', $url['query']);

echo $url['path'] . '?' . $url['query'];

您可以使用 lookbehind together with \K

$str = preg_replace('/(?<=\?)[^?]*\K\?/', "&", $str);

lookbehind 用于在要匹配的那个之前要求 ?[^?] 匹配任何不是 ? (negated character class) 的字符。 \K 重置报告匹配的开头。

Demo at regex101 or PHP demo at eval.in


或者使用 capturing group instead of \K: (?<=\?)([^?]*)\? and replace with &