在preg_match中排除字符串

时间:2014-03-26 20:01:57

标签: php regex

我有两个preg_match语句可以自己找到,但是当我使用它们时,第二个会打破第一个;

$message = preg_replace("!(http(s)?://(www\.|m\.)?(youtu\.be/|youtube\.com/watch\?v=)([-|~_0-9A-Za-z]+))!", 
"<p><a href= '/viewpost.php?messageid=$message_id'><img src='http://img.youtube.com/vi/$5/0.jpg' width='536' border='1'></a><p>", $message);

$message = preg_replace("!(((f|ht)tp(s)?://)[-a-zA-Z?-??-?()0-9@:%_+.~#?&;//=]+)!i", "<a href='$1' target='_blank' STYLE='TEXT-DECORATION: NONE'><b>$1</b></a>", 
$message);

我最近发布了这个,并收到了为模式和条件设置数组的建议,然后在单个preg_match语句中将它们一起应用,但这似乎没有解决问题(尽管代码看起来更好)。

我的想法是在第二个语句中设置一个模式,该模式将排除第一个语句中找到的模式(在本例中为“youtube.com/”和“youtu.be/”)但我无法获得它起作用了;

$message = preg_replace("!(http(s)?://(www\.|m\.)?(youtu\.be/|youtube\.com/watch\?v=)([-|~_0-9A-Za-z]+))!", 
"<p><a href= '/viewpost.php?messageid=$message_id'><img src='http://img.youtube.com/vi/$5/0.jpg' width='536' border='1'></a><p>", $message);

$message = preg_replace("!(((f|ht)tp(s)?://)/^(?\!\youtube\.|youtu\.be/)[-a-zA-Z?-??-?()0-9@:%_+.~#?&;//=]+)!i", "<a href='$1' target='_blank' STYLE='TEXT-DECORATION: NONE'><b>$1</b></a>", 
$message);

我认为我已经找到了一条路,但我没有抓到什么。

1 个答案:

答案 0 :(得分:1)

你几乎就在那里。在你的第二个preg_replace中,你有一些错误。

  1. 删除http部分之后的/^(斜杠不在那里且^仅匹配字符串的开头)
  2. 正则表达式没有编译,因为要排除的正确语法是?!(意思是没有后跟),并且它不能很好地与转义一起使用。我已选择#作为开放和关闭标记。
  3. 由于您已将youtu.be/...替换为img.youtube.com/...,因此您应该排除该网址。
  4. 工作代码:

    $message = 'http://youtu.be/watch?v=123 http://www.google.com';
    $message_id = 6;
    
    $message = preg_replace("!(http(s)?://(www\.|m\.)?(youtu\.be/|youtube\.com/watch\?v=)([-|~_0-9A-Za-z]+))!", 
    "<p><a href= '/viewpost.php?messageid=$message_id'><img src='http://img.youtube.com/vi/$5/0.jpg' width='536' border='1'></a><p>", $message);
    
    $message = preg_replace("#(((f|ht)tp(s)?://)(?!img.youtube.com/vi/)[-a-zA-Z?-??-?()0-9@:%_+.~\#?&;//=]+)#i", "<a href='$1' target='_blank' STYLE='TEXT-DECORATION: NONE'><b>$1</b></a>", 
    $message);
    
    echo htmlspecialchars($message);
    

    除此之外,使用preg_replace_callback的解决方案可能更容易阅读,并且使用将来的选项更容易扩展(例如,如果网址以.jpg结尾,则为内联图片):

    $message = 'http://youtu.be/watch?v=123 http://www.google.com';
    $message_id=6;
    
    $callback = function($matches) use ($message_id) {
        $youtube = preg_replace("!(http(s)?://(www\.|m\.)?(youtu\.be/|youtube\.com/watch\?v=)([-|~_0-9A-Za-z]+))!", 
    "<p><a href= '/viewpost.php?messageid=$message_id'><img src='http://img.youtube.com/vi/$5/0.jpg' width='536' border='1'></a><p>", $matches[0], -1, $count);
        if ($count) {
            return $youtube;
        } else {
            return "<a href='".$matches[0]."' target='_blank' STYLE='TEXT-DECORATION: NONE'><b>".$matches[0]."</b></a>";
        }
    };
    
    $message = preg_replace_callback("!(((f|ht)tp(s)?://)[-a-zA-Z?-??-?()0-9@:%_+.~#?&;//=]+)!i", $callback, $message);
    
    echo htmlspecialchars($message);
    

    (注意使用Closure $callback = function() { ... }至少需要PHP 5.3,否则你可以使用命名函数)