簡體   English   中英

正則表達式匹配和限制字符類

[英]Regex to match and limit character classes

我不確定使用Regex是否可行,但我希望能夠根據不同的字符限制允許的下划線數量。 這是為了將瘋狂的通配符限制限制為用Java編寫的搜索引擎。

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

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

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

是的,你可以做到。 : 只有當下划線少於字母時,此模式才會成功

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

否定版本:

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

我們的想法是重復一個包含對自身的反向引用+下划線的捕獲組。 在每次重復時,捕獲組都在增長。 ^(?:[AZ](?=[AZ]*+(\\\\1?+_)))*+將匹配具有對應下划線的所有字母。 您只需添加[AZ]+以確保有更多字母,並使用\\\\1?完成您的模式\\\\1? 包含所有下划線(我將其設為可選,以防根本沒有下划線)。

請注意,如果在第一個模式中將[AZ]+替換為[AZ]{n} ,則可以精確設置字母和下划線之間的字符數差異。


為了給出一個更好的想法,我將嘗試逐步描述它如何與字符串ABC-- (因為不可能將下划線以粗體顯示,我使用連字符代替):


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

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

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

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

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

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

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

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


注意:需要使用非捕獲組的占有量詞來避免錯誤結果。

示例: ABC---和模式: ^(?:[AZ](?=[AZ]*(\\1?+-)))*[AZ]+\\1?$


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

問題:捕獲組中有多少個連字符?
答:總是三個!

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

$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___'));

Robby Pond在評論中問我如何找到下划線比字母更多的字符串(所有這些都不是下划線) 顯然,最好的方法是計算下划線的數量並與字符串長度進行比較。 但是關於完整的正則表達式解決方案,由於模式需要使用遞歸功能,因此無法使用Java構建模式。 例如,你可以用PHP做到這一點:

 $pattern = <<<'EOD' ~ (?(DEFINE) (?<neutral> (?: _ \\g<neutral>?+ [AZ] | [AZ] \\g<neutral>?+ _ )+ ) ) \\A (?: \\g<neutral> | _ )+ \\z ~x EOD; var_dump(preg_match($pattern, '____ABC_DEF___')); 

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

i)需要實現邏輯以獲得下划線之前的字符數(應該編寫正則表達式以在下划線之前獲得字符)。

ii)並驗證結果(字符數 - 1)=所遵循的分號數(正則表達式返回下划線后跟字符)。

編輯:當! 我剛剛注意到你需要這個用於java。 無論如何......如果來自.Net世界的人偶然發現這篇文章,我就把它留在這里。

如果您使用.Net,則可以使用平衡組

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

.net正則表達式引擎能夠維護捕獲的組中的所有捕獲模式。 在其他類型中,捕獲的組將始終包含最后匹配的模式,但在.net中,所有先前的匹配都包含在捕獲集合中供您使用。 此外,.net引擎還能夠使用?<group-name>?<-group-name>構造來推送和彈出捕獲的組的堆棧。 這兩個方便的結構可用於匹配paranthesis對等。

在上面的正則表達式中,引擎從字符串的開頭開始,並嘗試匹配“_”以外的任何內容。 這當然可以改為適合你的任何東西(例如[AZ][az] )。 交替基本上意味着匹配[^\\_][\\_]並且這樣做可以從捕獲的組中推送或彈出。

正則表達式的后半部分是條件(?(group-name)true|false) 它基本上說,如果該組仍然存在(比彈出更多推送),那么執行true部分,如果不執行false部分。 使模式匹配的最簡單方法是使用空的正向前看: (?=)並且使其失敗的最簡單方法是(?!) ,這是一個負前瞻。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM