【问题标题】:How to ignore regex if part of a URL?如果是 URL 的一部分,如何忽略正则表达式?
【发布时间】:2014-01-02 13:38:29
【问题描述】:

在我的一个 PHP 网站上,我使用 this regular expression 自动从字符串中删除电话号码:

$text = preg_replace('/\+?[0-9][0-9()-\s+]{4,20}[0-9]/', '[removed]', $text);

但是,当用户发布包含多个数字作为其文本一部分的长 URL 时,该 URL 也会受到 preg_replace 的影响,从而破坏 URL。

如何确保上述preg_replace 不会更改$text 中包含的URL?

编辑:

根据要求,这是一个 URL 被上面的 preg_replace 破坏的示例:

$text = 'Please help me with my question here: https://stackoverflow.com/questions/20589314/  Thanks!';
$text = preg_replace('/\+?[0-9][0-9()-\s+]{4,20}[0-9]/', '[removed]', $text);
echo $text; 

//echoes: Please help me with my question here: https://stackoverflow.com/questions/[removed]/ Thanks!

【问题讨论】:

  • 只需检查违规文本是否以“http”开头。
  • @nietonfir:但是如果 URL 在文本中间呢?
  • 我认为您必须解析网址和电话号码,例如/(?: url \K | phone number)/
  • 请提供几个带有电话号码的 URL 示例,以及它们是如何被破坏的
  • @sln:我该怎么做?如果有帮助,这里有一个 URL 正则表达式:stackoverflow.com/a/8234912/869849

标签: php regex string url preg-replace


【解决方案1】:

我认为您必须解析网址和电话号码,例如/(?: url \K | phone number)/ - sln
@sln:我该怎么做?如果有帮助,这里有一个 URL 正则表达式:stackoverflow.com/a/8234912/869849 – ProgrammerGirl

这是一个使用提供的正则表达式作为 url 和电话号码的示例:

php测试用例

 $text = 'Please help me with my +44-83848-1234 question here: http://stackoverflow.com/+44-83848-1234questions/20589314/ phone #:+44-83848-1234-Thanks!';
 $str = preg_replace_callback('~((?:(?:[a-zA-Z]{3,9}:(?://)?)(?:[;:&=+$,\w-]+@)?[a-zA-Z0-9.-]+|(?:www\.|[;:&=+$,\w-]+@)[a-zA-Z0-9.-]+)(?:(?:/[+\~%/.\w-]*)?\??[+=&;%@.\w-]*\#?\w*)?)|(\+?[0-9][0-9()\s+-]{4,20}[0-9])~',
                   function( $matches ){
                        if ( $matches[1] != "" ) {
                             return $matches[1];
                        }
                        return '[removed]';
                   },
                   $text);

 print $str;

输出>>

 Please help me with my [removed] question here: http://stackoverflow.com/+44-83848-1234questions/20589314/ phone #:[removed]-Thanks!

正则表达式,用RegexFormat处理

 # '~((?:(?:[a-zA-Z]{3,9}:(?://)?)(?:[;:&=+$,\w-]+@)?[a-zA-Z0-9.-]+|(?:www\.|[;:&=+$,\w-]+@)[a-zA-Z0-9.-]+)(?:(?:/[+\~%/.\w-]*)?\??[+=&;%@.\w-]*\#?\w*)?)|(\+?[0-9][0-9()\s+-]{4,20}[0-9])~'

     (                                  # (1 start), URL
          (?:
               (?:
                    [a-zA-Z]{3,9} :
                    (?: // )?
               )
               (?: [;:&=+$,\w-]+ @ )?
               [a-zA-Z0-9.-]+ 
            |  
               (?: www \. | [;:&=+$,\w-]+ @ )
               [a-zA-Z0-9.-]+ 
          )
          (?:
               (?: / [+~%/.\w-]* )?
               \??
               [+=&;%@.\w-]* 
               \#?
               \w* 
          )?
     )                                  # (1 end)
  |  
     (                                  # (2 start), Phone Num
          \+? 
          [0-9] 
          [0-9()\s+-]{4,20} 
          [0-9] 
     )                                  # (2 end)

【讨论】:

  • 非常有趣,谢谢!有没有办法只使用 1 行 preg_replace 来做到这一点?
  • 而不是 preg_replace_callback 的 1 行?要看换什么了。正如我之前所说,preg_replace /(?: url \K | phone number)/ 与 ""。
  • 我尝试了您在评论中提到的内容,它正确地忽略了 URL,但是,它将“[removed]”附加到 URL 的末尾。你知道怎么解决吗?
  • 有两难选择。如果替换为空字符串,则可以使用简单的preg_replace 来完成。 URL 必须独立使用才能通过它,因为电话号码是它的子集。在这种情况下,没有实用的方法来使用断言。在正则表达式引擎中,回调是一个简单的额外函数调用,实际上是难以察觉的开销。如果你想完成工作,我建议使用这种方法。
【解决方案2】:

您应该进行更多编码,这样您就可以抚摸自己的自我了!

<?php
    $text = "This is my number20558789yes with no spaces
    and this is yours 254785961
    But this 20558474 is within http://stackoverflow.com/questions/20558474/
    So I don't remove it
    and this is another url http://stackoverflow.com/questions/20589314/ 
    Thanks!";
    $up = "(https?://[-.a-zA-Z0-9]+\.[a-zA-Z]{2,3}/\S*)"; // to catch urls
    $np = "(\+?[0-9][0-9()-\s+]{4,20}[0-9])"; // you know this pattern already
    preg_match_all("#{$up}|{$np}#", $text, $matches); // match all above patterns together ($matches[1] contains urls, $matches[2] contains numbers)
    preg_match_all("#{$np}#", print_r(array_filter($matches[1]), true), $urls_numbers); // extract numbers from urls, actually if we have any
    $diff = array_diff(array_filter($matches[2]), $urls_numbers[0]); // an array with numbers that we should replace
    $text = str_replace($diff, "[removed]", $text); // replacing
    echo $text; // here you are

然后输出

This is my number[removed]yes with no spaces
and this is yours [removed]
But this 20558474 is within http://stackoverflow.com/questions/20558474/
So I don't remove it
and this is another url http://stackoverflow.com/questions/20589314/ 
Thanks!

【讨论】:

    【解决方案3】:

    假设电话号码通常以空格开头或位于行首是否公平?如果是这样,这将阻止您意外更改 URL,因为 URL 中间不存在空格或换行符:

    $text = preg_replace('/(^|\s)\+?[0-9][0-9()-\s+]{4,20}[0-9]/', '[removed]', $text);
    

    【讨论】:

    • 您的解决方案的问题在于,只需在电话号码前加上一个字母,就可以轻松(并且意外地!)绕过它。理想情况下,我正在寻找一种解决方案,如果数字序列出现在 URL 中,则只会忽略正则表达式,但我不知道该怎么做。
    猜你喜欢
    • 1970-01-01
    • 2018-08-24
    • 2022-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-31
    • 2021-12-28
    • 1970-01-01
    相关资源
    最近更新 更多