preg_replace的奇怪行为

时间:2013-03-05 16:09:23

标签: php regex

我想切换链接的协议。如果是http,它应该成为https,https应该成为http。我正在使用pre_replace但是出了问题。

有人可以查看我的代码并告诉我在思考过程中缺少的是什么吗?

以下是代码:

           $pattern = array(
                0 => '/^(http\:)/',
                1 => '/^(https\:)/'
            );
            $replace = array(
                0 => 'https:',
                1 => 'http:'
            );

            ksort($pattern);
            ksort($replace);

            $url = 'http://someurl.com';

            echo $url."<br />";

            $url = preg_replace($pattern, $replace, trim($url),1);

            die($url);

5 个答案:

答案 0 :(得分:3)

  1. 你不需要逃避:,它不是一个特殊角色。
  2. 您不需要捕获组()
  3. 您无需致电ksort(),您的数组在声明时已按键排序。
  4. 您的代码似乎将“http”替换为“https” AND 将“https”替换为“http”。为什么?
  5. 如果您只是想强制使用https,那么

    $url = preg_replace('/^http:/', 'https', trim($url));会正常工作。

    修改

    我仍然不知道为什么有人想要同时切换http / https,但是你走了:

    function protocol_switcheroo($url) {
      if( preg_match('/^http:/', $url) ) {
        return preg_replace('/^http:/', 'https:', $url); // http to https
      } else if( preg_match('/^https:/', $url) ) {
        return preg_replace('/^https:/', 'http:', $url); // https to http
      } else {
        return $url; // for URIs with protocols other than http/https
      }
    }
    

    您需要将要更换的调用分开,这样您就不会像问题中的原始代码那样意外地将它们链接起来。

答案 1 :(得分:1)

这不适用于http的原因 - &gt; https(但适用于https - &gt; http)是preg_replace()首先使用第一组键/变量(0)将http更改为https,但随后立即返回到https - &gt; http,因为每个数组中的第二组变量(1)是另一个有效匹配。

答案 2 :(得分:1)

//$url = 'http://example.com/https://www';
$url = 'https://example.com/http://www';

$url = (0 === strpos($url, 'http:'))
    ? substr_replace($url, 's:', 4, 1)
    : substr_replace($url, '', 4, 1);

echo $url;

这会转换HTTP -> HTTPSHTTPS -> HTTP

它不使用速度较慢的正则表达式,并且不使用可能无意中替换URL的其他部分的str_replace()。它只会替换第一个前缀。

细分:它会查看网址是否以http:开头,是否会将第5个字符:替换为s:,并将其设为HTTPS。否则它将替换第5个字符s,而不会使其成为HTTP。

答案 3 :(得分:0)

您的网址已被替换两次。首先,第一个表达式匹配,http://someurl.com变为https://someurl.com。然后,第二个表达式匹配,https://someurl.com变为http://someurl.com

通过另一个例子更容易看到:

echo preg_replace(
    array('/fox/',  '/turtle/'),
    array('turtle', 'sparrow'),
 'fox', 1);

...打印sparrow

答案 4 :(得分:0)

你遇到的问题是preg_replace()一个接一个地做两个替换,所以在第一个替换之后,第二个替换了第一个的效果。

您需要在单个表达式中指定这两种模式,以便让它们一起运行。

我建议使用preg_replace_callback()代替preg_replace()。通过这种方式,您可以编写更复杂的输出表达式,从而更容易将它们组合成单个模式。这样的事情可以解决问题:

$outputString = preg_replace_callback(
    '/^(http|ftp)(s)?(:)/',
    function($matches) {return $matches[1].($matches[2]=='s'?'':'s').':';},
    $inputString
);

希望有所帮助。

[编辑]编辑了代码,以便在OP发表评论后适用于ftp / ftps以及http / https