如何解决这个@mention正则表达式?

时间:2017-02-08 02:21:55

标签: javascript regex

我想捕获@usernames的提及。用户名具有以下规则:

  • 仅限小写字母,数字或点(。)
  • 没有以点开头或结尾
  • 连续不超过一个点(例如,不允许使用user..name,但是us.er.name是)

所以,我想出了这个:

/(?:^|\s)(@)(?!\.)(?!.*\.\.)(?!.*\.[\s|$])([a-z0-9\.]+)(?:\s|$)/gm;

这应该意味着:

 (?:^|\s) starting at start of line, or with a whitespace
         (@) having a @
            (?!\.) name not starting with a dot
                  (?!.*\.\.) not containing two adjacent dots (..)
                            (?!.*\.[\s|$]) not ending with a dot (yes this sucks)
                                          ([a-z0-9\.]+) allowed chars
                                                       (?:\s|$) ending at EOL or whitespace

作为一个具有正则表达式的完整菜鸟,我很高兴看到这是如何使用长的多行测试字符串执行的。 但后来我尝试了最简单的测试字符串,如:

@foo @bar I hate you both.

在这种情况下foo被捕获,但bar不是。我想,即使我使用非捕获组,@foo也会占用以下空格,因此@bar(?:^|\s)处失败。

如何编辑此正则表达式以使其正常工作?

请不要建议完全不同的@mention正则表达式,我可以很好地搜索它们,因为还有其他问题。我只想让它工作,并知道它为什么没有。

3 个答案:

答案 0 :(得分:2)

通常,您在这里遇到的问题是您在单词的开头和结尾使用了捕获组,这意味着这些字符会从进一步的RegEx匹配中消耗掉。

这是因为你这样做:(?:...)

相反,您可以使用一类特殊的捕获组,它们不使用名为Lookahead的字符:(?=...)

在RegEx中,有Lookbehind AND Lookahead,它分别在RegEx之前和之后进行检查。对你的问题的完美答案将使用lookbehind作为字符串(?<=^|\s)的开头,并使用lookahead作为字符串(?=\s|$)的结尾。不幸的是,在Javascript中,不支持Lookbehind,但是为了满足您的特定需求,我们可以解决这个问题。

如果我们确保不捕获用户名末尾的尾随空格,那么它可以用于匹配您在RegEx开头定义的捕获组。这是代码:

(?:^|\s)(@)(?!\.)(?!\S*\.\.)(?!\S*\.[\s|$])([a-z0-9\.]+)(?=\s|$)

注意除了&#39; =&#39;之外,一切都差不多。在最后一节,&#39; \ S&#39;在&#39;没有以点为结尾&#39;部分和&#39;不包含两个相邻的点&#39;,您在下面的评论中找到了这些点。

可以找到结果here。不幸的是,这将返回与其中的空间完全匹配的&#34; @ bar&#34;,但该匹配的子组看起来仍然很好。

请告诉我这是否有帮助!

答案 1 :(得分:0)

这个正则表达式将完成工作:

@[0-9a-z](\.?[0-9a-z])*

如以下demo所示。

答案 2 :(得分:0)

有两种类型的提及,像 facebook 这样的有空格和没有像 twitter 这样的空格:

没有空间(如推特):

(?:^|\\s|$|[.])@[\\p{L}0-9_]*

对于空间(如facebook):

@[[\\p{L}0-9_]*(\\s)?[\\p{L}0-9_]*]*