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

时间:2016-06-22 08:03:42

标签: php regex preg-replace

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

$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

如何忽略?的第一次出现?

6 个答案:

答案 0 :(得分:4)

将字符串的开头与第一个?匹配,并使用(*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])的帮助下检查小组是否匹配("参加了比赛")。如果是,我们就把它放回去。如果没有,[?],第二个分支匹配,那么,我们将其替换。

答案 1 :(得分: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;

答案 2 :(得分:0)

不知道这是否是最干净的方式,但是会起作用并且很容易:

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

答案 3 :(得分:0)

最好的方法是我认为是explode("?",$str)explode("&",$str)并将它们放在一个数组中并使用小的if条件preg_replace()进行第一次?你要忽略并做array_marge()

尝试并让我知道

答案 4 :(得分:0)

请参阅parse_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'];

答案 5 :(得分:0)

您可以将lookbehind\K

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

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

Demo at regex101PHP demo at eval.in

或者使用capturing group代替\K(?<=\?)([^?]*)\? and replace with $1&