【问题标题】:Regex: how to match any string until whitespace, or until punctuation followed by whitespace?正则表达式:如何匹配任何字符串直到空格,或者直到标点符号后跟空格?
【发布时间】:2013-05-31 16:27:49
【问题描述】:

我正在尝试编写一个正则表达式,它将在纯文本字符串中查找 URL,以便我可以用锚标记包装它们。我知道有expressions already available for this,但我想创建自己的,主要是因为我想知道它是如何工作的。

如果我的正则表达式失败,它不会破坏任何东西,我的计划是写一些相当简单的东西。到目前为止,这意味着:1)在单词的开头匹配“www”或“http”2)继续匹配直到单词结束。

我可以做到,AFAICT。我有这个:\b(http|www).?[^\s]+

适用于foo www.example.com bar http://www.example.com 等。

问题是,如果我给它foo www.example.com, http://www.example.com,它会认为逗号是 URL 的一部分。

所以,如果我要使用一个表达式来执行此操作,我需要将“...并在您看到空格时停止”更改为“...并在您看到空格或空格之前的一段标点符号时停止”。 我不知道该怎么做。

目前,我正在考虑使用的解决方案只是添加另一个测试 - 匹配 URL,然后在下一行移动任何偷偷摸摸的标点符号。这不是那么优雅。

注意:我是用 PHP 编写的。

旁白:为什么在上面的表达式中用\b 替换\s 似乎不起作用?


预计到达时间:

谢谢大家!

根据 Explosion Pills 的建议,这就是我最终得到的结果:

function add_links( $string ) {
    function replace( $arr ) {
        if ( strncmp( "http", $arr[1], 4) == 0 ) {
            return "<a href=$arr[1]>$arr[1]</a>$arr[2]$arr[3]";
        } else {
            return "<a href=" . "http://" . $arr[1] . ">$arr[1]</a>$arr[2]$arr[3]";
        }
    }
return preg_replace_callback( '/\b((?:http|www).+?)((?!\/)[\p{P}]+)?(\s|$)/x', replace, $string );
}

我添加了一个回调,以便所有链接都以 http:// 开头,并对它处理标点符号的方式做了一些调整。

这可能不是最好的做事方式,但它确实有效。在过去的一段时间里,我学到了很多这方面的知识,但还有很多东西要学!

【问题讨论】:

  • 嗨@Nick,欢迎来到SO。 +1 格式正确的问题 :)
  • 谢谢,谢谢!

标签: php regex url


【解决方案1】:
preg_replace('/
    \b       # Initial word boundary
    (        # Start capture
    (?:      # Non-capture group
    http|www # http or www (alternation)
    )        # end group
    .+?      # reluctant match for at least one character until...
    )        # End capture
    (        # Start capture
    [,.]+    # ...one or more of either a comma or period.
             # add more punctuation as needed
    )?       # End optional capture
    (\s|$) # Followed by either a space character or end of string
    /x', '<a href="\1">\1</a>\2\3'

...可能是你想要的。我认为它仍然不完美,但至少应该可以满足您的需求。

旁白:我认为这是因为\b 也匹配标点符号

【讨论】:

  • 这是解释正则表达式的好方法!
【解决方案2】:

您可以通过positive lookahead assertion 实现此目的:

\b(http:|www\.)(?:[^\s,.!?]|[,.!?](?!\s))+

here on Regexr

意思是,匹配任何东西,但空格 ,.!? 或匹配 ,.!?,当它后面没有空格时。

除此之外:word boundary 不是一个字符或一组字符,您不能将其放入字符类中。这是一个零宽度断言,即匹配从单词字符到非单词字符的变化。在这里,我相信,字符类中的\b 被解释为退格字符(字符串转义序列)。

【讨论】:

    【解决方案3】:

    问题可能出在点上,它在正则表达式中表示“任何字符”。你可能不得不逃避它:

    \b(http|www)\.?[^\s]+
    

    那么,问号表示 0 或 1,所以你说的是“可选点”,这不是你想要的(对吗?):

    \b(http|www)\.[^\s]+
    

    现在,它只会匹配 http.www. 所以你需要告诉它你会接受哪些其他字符:

    \b(http|www)\.[^\s\w]+
    

    \b(http|www)\.[^\sa-zA-Z]+
    

    所以现在你是说,

    • 单词的边界
    • 检查httpwww
    • 打个点
    • 允许任何范围a-zA-Z,不允许任何空白字符
    • 其中一个或多个

    注意 - 我没有测试过这些,但希望它们是正确的。


    除此之外(我的看法) - \s 表示“空白”。 \b 表示“单词边界”。 [] 表示“允许的字符范围”。 ^ 表示“不”。 + 表示“一个或多个”。

    因此,当您说[^\b]+ 时,您是在说“不允许此字符范围内的单词边界,并且必须有一个或多个”,因为那里没有其他内容 > 没有其他内容 > 没有或更多 > 它可能会坏掉。

    【讨论】:

    • 一个词的边界不是一个字符或一组字符,你不能把它放到一个字符类中。这是一个零宽度断言,即匹配从单词字符到非单词字符的变化。在这里,我相信,字符类中的\b 被解释为退格字符(字符串转义序列)。
    • 点是可选的,因为http后面没有点,所以从http上就不会匹配了。
    【解决方案4】:

    你应该试试这样的:

    \b(http|www).?[\w\.\/]+
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-26
      • 2016-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多