2017-02-08 56 views
1

我想要提及@ usernames。用戶名有以下規則:(。)如何解決這個@mention正則表達式?

  • 只有小寫字母,數字或點
  • 沒有啓動或以一個點
  • 不超過連續一個點結束(如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 

作爲一個正則表達式的完整noob,我很高興看到這是如何執行一個長的多行測試字符串。 但後來我想最簡單的測試字符串,如:

@foo @bar I hate you both. 

在這種情況下,富時抓住了,但酒吧不是。我想,即使我使用非捕獲組,@foo也需要以下空格,所以@bar失敗,在(?:^|\s)

我應該如何修改這個正則表達式來有它的工作?

請不要建議完全不同的@mention正則表達式,我可以很好地尋找他們,因爲有其他問題。我只想讓這個工作,並知道爲什麼不這樣做。

+0

你想要發生什麼「@ foo @ bar」? –

+0

@Shawn根本就沒有抓到,兩者之間必須有空白。 – natario

+0

如果您使用Lookbehind([示例](https://regex101.com/r/ypzKoJ/1)),那麼您的RegEx完美工作,但是我確定您知道Javascript不支持該功能。最好的辦法是嘗試將lookbehind轉換成lookahead和條件語句。 –

回答

2

一般情況下,你有這裏的問題是,你使用的是捕獲組一個單詞,這意味着這些字符是從進一步的正則表達式匹配消耗的開頭和結尾的空間。

這是因爲你做的事:(?:...)

相反,你可以使用一類特殊的捕捉組不消耗字符,叫做先行的:(?=...)

在正則表達式,有回顧後和預讀,這之前檢查並分別在正則表達式之後。對於您的問題的完美答案將使用字符串(?<=^|\s)的開頭和後向字符串(?=\s|$)的末尾。不幸的是,在Javascript中,Lookbehind不被支持,但爲了您的具體需求,我們可以解決這個問題。

如果我們確保不會在用戶名的末尾捕捉尾隨空格,那麼它可以用來配合你的正則表達式的開頭定義的捕獲組。下面是該代碼:

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

注一切除了「=」在最後一節幾乎一樣,和「\ S」一節中「不能以點結束的」和「不包含兩個相鄰點',你在下面的評論中抓到了。

結果可以發現here。不幸的是,這會返回與「@bar」中的空格完全匹配的內容,但該匹配的子組仍然很好看。

讓我知道這是否有幫助!

+0

謝謝。我明天將會看到它,現在。現在是否應該重寫「不以點結尾」的條件?由於尾隨空間不再被捕獲。我的意思是(?!。* \。[\ s | $]) – natario

+0

好,你需要把它改成'(?!\ S * \。[\ s | $])'不是空格字符的字符,否則爲「@foo @bar」。將不會找到任何用戶名。我會更新我的答案和示例。 –

+0

您還需要將'(!!。* \。\。)'從「不包含兩個相鄰的點」更新爲'(!!\ S * \。\。)' –

0

這個規則表達式將做的工作:

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

如見於以下demo