2014-05-21 25 views
5

我不確定這是否可以使用正則表達式,但是我希望能夠根據不同的字符限制允許的下劃線的數量。這是爲了將瘋狂的通配符查詢限制爲用Java編寫的搜索引擎。用於匹配和限制字符類的正則表達式

起始字符是字母數字。但是我基本上想要一個匹配,如果有更多的下劃線比前面的字符。所以

BA_會很好,但BA___將匹配正則表達式,並將被踢出查詢解析器。

使用正則表達式有可能嗎?

+1

我個人只是匹配一組中的字母,在另一組中強調下劃線,然後斷言第二組的長度比第一組長。 – roippi

+0

@roippi我將正則表達式傳遞到另一個工具,所以它需要在一個表達式中。 –

回答

8

是的,你可以做到這一點。這種模式會成功的前提有下劃線小於信(您可以用文字適應它,你想要的)

^(?:[A-Z](?=[A-Z]*(\\1?+_)))*+[A-Z]+\\1?$ 

(如Pshemo注意到它,不需要錨如果您使用matches()方法,我寫他們來說明這樣一個事實,即無論如何,這種模式必須受到限制。)

否定版本:

^(?:[A-Z](?=[A-Z]*(\\1?+_)))*\\1?_*$ 

的想法是重複包含反向引用本身+下劃線捕獲組。在每次重複中,捕獲組都在不斷增長。 ^(?:[A-Z](?=[A-Z]*+(\\1?+_)))*+將匹配具有相應下劃線的所有字母。您只需要添加[A-Z]+以確保有更多字母,並使用包含所有下劃線的\\1?來完成您的模式(如果根本沒有下劃線,我將其設置爲可選項)。

請注意,如果在第一種模式中將[A-Z]+替換爲[A-Z]{n},則可以精確地設置字母和下劃線之間的字符數量差異。


爲了給出一個更好的主意,我會盡量一步來形容一步如何與字符串ABC--工作(因爲它是不可能把下劃線加粗,我用,而不是連字符):

 
 In the non-capturing group, the first letter is found 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$ 
 let's enter the lookahead (keep in mind that all in the lookahead is only 
a check and not a part of the match result.) 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$ 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
 the first capturing group is encounter for the first time and its content is not 
defined. This is the reason why an optional quantifier is used, to avoid to make 
the lookahead fail. Consequence: \1?+ doesn't match something new. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
 the first hyphen is matched. Once the capture group closed, the first capture 
    group is now defined and contains one hyphen. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
The lookahead succeeds, let's repeat the non-capturing group. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
The second letter is found 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$ 
We enter the lookahead 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
but now, things are different. The capture group was defined before and 
contains an hyphen, this is why \1?+ will match the first hyphen. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$ 
the literal hyphen matches the second hyphen in the string. And now the 
capture group 1 contains the two hypens. The lookahead succeeds. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
We repeat one more time the non capturing group. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$ 
In the lookahead. There is no more letters, it's not a problem, since 
the * quantifier is used. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$ 
\\1?+ matches now two hyphens. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
but there is no more hyphen in the string for the literal hypen and the regex engine can not use the bactracking since \1?+ has a possessive quantifier. 
The lookahead fails. Thus the third repetition of the non-capturing group too! 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$ 
ensure that there is at least one more letter. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
We match the end of the string with the backreference to capture group 1 that 
contains the two hyphens. Note that the fact that this backreference is optional 
allows the string to not have hyphens at all. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$ 
This is the end of the string. The pattern succeeds. 
ABC--  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$ 


注意:需要使用非捕獲基團的使用的所有格量詞的,以避免虛假結果。 (在這裏您可以看到一個奇怪的現象,這可能是有用的。)

例子:ABC---和模式:^(?:[A-Z](?=[A-Z]*(\1?+-)))*[A-Z]+\1?$(沒有佔有慾量詞)

 
The non-capturing group is repeated three times and `ABC` are matched: 
ABC---  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*[A-Z]+\1?$ 
Note that at this step the first capturing group contains --- 
But after the non capturing group, there is no more letter to match for [A-Z]+ 
and the regex engine must backtrack. 
ABC---  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*[A-Z]+\1?$ 

問:多少連字符現在在捕獲組中嗎?
答案:  總是三個!

如果重複的非捕獲組返回一個字母,則捕獲組始終包含三個連字符(作爲正則表達式引擎讀取捕獲組的最後一次)。這是違反直覺的,但是合乎邏輯的。

 
Then the letter C is found: 
ABC---  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*[A-Z]+\1?$ 
And the three hyphens 
ABC---  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*[A-Z]+\1?$ 
The pattern succeeds 
ABC---  ^(?:[A-Z](?=[A-Z]*(\1?+-)))*[A-Z]+\1?$

羅比池問我怎麼樣找到比字母多個下劃線的字符串(所有不是下劃線)。顯然,最好的方法是計算下劃線的數量並與字符串長度進行比較。但是關於完整的正則表達式解決方案,由於模式需要使用遞歸功能,因此不可能爲Java構建模式。例如,你可以用PHP做到這一點:

$pattern = <<<'EOD' 
~ 
(?(DEFINE) 
    (?<neutral> (?: _ \g<neutral>?+ [A-Z] | [A-Z] \g<neutral>?+ _)+) 
) 

\A (?: \g<neutral> | _)+ \z 
~x 
EOD; 

var_dump(preg_match($pattern, '____ABC_DEF___')); 
+0

正則表達式的這種味道是什麼?我覺得這很有趣。你能再解釋一下嗎?我發現很難理解遞歸部分。 Regex101並沒有真正的幫助。它甚至不匹配。你能否提供一個可以測試上述正則表達式的網站? –

+0

@FarhadAliNoo:它是Java的一個版本,但同樣的技術也可以與PCRE一起使用。看看這篇文章:http://stackoverflow.com/questions/23001137/capturing-quantifiers-and-quantifier-arithmetic/23002044#23002044 –

+1

@FarhadAliNoo:我會盡力解釋更多。 –

0

它在單數正則表達式中是不可能的。

i)需要執行邏輯以獲取下劃線之前的字符數(正則表達式應寫入以獲取下劃線之前的字符單詞)。

ii)驗證結果(字符數-1)=後面跟着分號的數字(返回字符後跟下劃線的正則表達式)。

0

編輯:當!我只注意到你需要這個用於java。反正......如果有人來自.Net世界,這個帖子就絆倒了。

你可以,如果你使用的是.NET使用Balancing Groups

^(?:(?<letter>[^_])|(?<-letter>_))*(?(letter)(?=)|(?!))$ 

的.NET正則表達式引擎必須保持在捕獲組中的所有攝像圖案的能力。在其他風格中,捕獲的組總是包含最後匹配的模式,但是.net中的所有以前的匹配都包含在捕獲集合中供您使用。此外.net引擎還可以使用?<group-name>,?<-group-name>結構推送和彈出到捕獲的組的堆棧。這兩個方便的構造可以用來匹配painthesis對等。

在上面的正則表達式中,引擎從字符串的開始處開始並嘗試匹配除「_」以外的任何內容。這當然可以改變爲適合你的任何東西(例如[A-Z][a-z])。交替基本上意味着或者匹配[^\_][\_],並且從捕獲的組中按下或彈出。

正則表達式的後半部分是條件式(?(group-name)true|false)。它基本上說,如果該羣體仍然存在(比彈出更多的推動),那麼做真正的部分,如果不這樣做的假部分。使模式匹配的最簡單方法是使用空的積極外觀:(?=)並使其失敗的最簡單方法是(?!),這是一種負面預測。