日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java正则表达式 n_如何将a^nb^n与Java正则表达式匹配?

發(fā)布時間:2024/3/26 java 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java正则表达式 n_如何将a^nb^n与Java正则表达式匹配? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

答案是,不用說,是!當(dāng)然,您可以編寫一個Java regex模式來匹配anbn..它使用一個積極的前瞻性斷言,一個嵌套的引用用于“計(jì)數(shù)”。

這個答案將引導(dǎo)讀者閱讀,而不是立即給出答案。過程得到它。隨著解的緩慢構(gòu)造,給出了各種提示。在這方面,希望這個答案包含的不僅僅是另一個整潔的regex模式。希望讀者還將學(xué)習(xí)如何“在regex中思考”,以及如何將各種結(jié)構(gòu)和諧地組合在一起,以便在將來能夠自己派生出更多的模式。

開發(fā)解決方案所用的語言將是PHP,因?yàn)樗啙崱R坏┳罱K確定了模式,最后的測試將在Java中完成。

步驟1:展望斷言

讓我們從一個簡單的問題開始:我們想要匹配a+在字符串的開頭,但前提是它緊跟在b+..我們可以用^到錨因?yàn)槲覀冎幌肫ヅ鋋+沒有b+,我們可以用前瞻斷言(?=…).

下面是我們使用一個簡單測試工具的模式:

function testAll($r, $tests) {

foreach ($tests as $test) {

$isMatch = preg_match($r, $test, $groups);

$groupsJoined = join('|', $groups);

print("$test $isMatch $groupsJoined\n");

}

}

$tests = array('aaa', 'aaab', 'aaaxb', 'xaaab', 'b', 'abbb');

$r1 = '/^a+(?=b+)/';

#? ? ? ? ? └────┘

#? ? ? ? ?lookahead

testAll($r1, $tests);

輸出是(如ideone.com所見):

aaa 0

aaab 1 aaa

aaaxb 0

xaaab 0

b 0

abbb 1 a

這正是我們想要的輸出:我們匹配a+,只有當(dāng)它位于字符串的開頭,并且它的后面緊跟著b+.

教課:您可以在“旁觀者”中使用模式來進(jìn)行斷言。

步驟2:以向前看的方式捕獲(和f r e-s p a c i n g模式)

現(xiàn)在讓我們說,即使我們不想b+作為比賽的一部分,我們確實(shí)想俘獲同樣,由于我們預(yù)計(jì)有一個更復(fù)雜的模式,讓我們使用x改性劑自由間距這樣我們就可以讓正則表達(dá)式更易讀了。

在前面的PHP片段的基礎(chǔ)上,我們現(xiàn)在有了以下模式:

$r2 = '/ ^ a+ (?= (b+) ) /x';

#? ? ? ? ? ? ?│? ?└──┘ │

#? ? ? ? ? ? ?│? ? ?1? │

#? ? ? ? ? ? ?└────────┘

#? ? ? ? ? ? ? lookahead

testAll($r2, $tests);

輸出現(xiàn)在是(如ideone.com所見):

aaa 0

aaab 1 aaa|b

aaaxb 0

xaaab 0

b 0

abbb 1 a|bbb

請注意,例如。aaa|b是.的結(jié)果join-了解每一組被捕獲的內(nèi)容'|'..在這種情況下,組0(即模式匹配的內(nèi)容)捕獲。aaa,第一組被俘b.

教課:你可以在一個環(huán)顧四周的地方捕捉到。你可以使用自由間距來提高可讀性.

步驟3:將前瞻性重構(gòu)為“循環(huán)”

在我們引入我們的計(jì)數(shù)機(jī)制之前,我們需要對我們的模式做一次修改。當(dāng)前,前瞻性不在+重復(fù)“循環(huán)”。到目前為止還好,因?yàn)槲覀冎皇窍霐嘌詁+跟隨我們a+但是我們真的最后要做的是為每個人斷言a我們在“循環(huán)”中匹配,有一個對應(yīng)的b一起去吧。

現(xiàn)在我們不要擔(dān)心計(jì)數(shù)機(jī)制,只需按照以下步驟進(jìn)行重構(gòu):

第一次重構(gòu)a+到(?: a )+(請注意,(?:…)是一個非捕獲組)

然后在這個非捕獲組中移動前瞻。

請注意,我們現(xiàn)在必須“跳過”a*在我們“看到”之前b+,因此相應(yīng)地修改模式。

因此,我們現(xiàn)在有以下幾點(diǎn):

$r3 = '/ ^ (?: a (?= a* (b+) ) )+ /x';

#? ? ? ? ? │? ? ?│? ? ? └──┘ │ │

#? ? ? ? ? │? ? ?│? ? ? ? 1? │ │

#? ? ? ? ? │? ? ?└───────────┘ │

#? ? ? ? ? │? ? ? ?lookahead? ?│

#? ? ? ? ? └───────────────────┘

#? ? ? ? ? ?non-capturing group

輸出與以前相同(如ideone.com所見),所以在這方面沒有任何變化。重要的是,現(xiàn)在我們的斷言是每一次迭代.的.+“循環(huán)”對于我們當(dāng)前的模式,這是不必要的,但接下來我們將使用自引用使第1組“計(jì)數(shù)”。

教課:您可以在非捕獲組中捕獲。環(huán)顧四周是可以重復(fù)的。

第四步:這是我們開始計(jì)數(shù)的步驟。

下面是我們要做的事情:我們將重寫第一組,這樣:

的第一次迭代結(jié)束時,+,當(dāng)?shù)谝淮蝍是匹配的,它應(yīng)該捕獲b

在第二次迭代結(jié)束時,當(dāng)另一個a是匹配的,它應(yīng)該捕獲bb

在第三次迭代結(jié)束時,它應(yīng)該捕獲bbb

...

在n-第四次迭代,第一組應(yīng)該捕獲bn

如果沒有足夠的b要捕獲到第1組,斷言就會失敗。

第一組,現(xiàn)在(b+),將不得不重寫為(\1 b)..也就是說,我們試圖“添加”一個b在上一次迭代中捕獲了哪些組1。

這里有一個小問題,因?yàn)檫@個模式缺少了“基本案例”,即它可以在沒有自引用的情況下進(jìn)行匹配。因?yàn)榻M1啟動“未初始化”,所以需要一個基本的大小寫;它還沒有捕獲任何內(nèi)容(甚至沒有一個空字符串),所以自引用嘗試總是失敗的。

有很多種方法可以解決這個問題,但是現(xiàn)在讓我們來做一個自引用匹配。任選,即.\1?..這可能是完美的,也可能不是完美的,但讓我們看看它能起什么作用,如果有什么問題,當(dāng)我們到達(dá)它的時候,我們會穿過那座橋。同時,我們還將在測試用例中添加更多的測試用例。

$tests = array(

'aaa', 'aaab', 'aaaxb', 'xaaab', 'b', 'abbb', 'aabb', 'aaabbbbb', 'aaaaabbb'

);

$r4 = '/ ^ (?: a (?= a* (\1? b) ) )+ /x';

#? ? ? ? ? │? ? ?│? ? ? └─────┘ | │

#? ? ? ? ? │? ? ?│? ? ? ? ?1? ? | │

#? ? ? ? ? │? ? ?└──────────────┘ │

#? ? ? ? ? │? ? ? ? ?lookahead? ? │

#? ? ? ? ? └──────────────────────┘

#? ? ? ? ? ? ?non-capturing group

輸出現(xiàn)在是(如ideone.com所見):

aaa 0

aaab 1 aaa|b? ? ? ? # (*gasp!*)

aaaxb 0

xaaab 0

b 0

abbb 1 a|b? ? ? ? ? # yes!

aabb 1 aa|bb? ? ? ? # YES!!

aaabbbbb 1 aaa|bbb? # YESS!!!

aaaaabbb 1 aaaaa|bb # NOOOOOoooooo....

哈哈!看來我們現(xiàn)在離解決方案很近了!我們設(shè)法讓第一組使用自我引用“計(jì)數(shù)”!但是等等.。第二個和最后一個測試用例出了問題!沒有足夠的bS,不知怎么算錯了!我們將在下一步研究為什么會發(fā)生這種情況。

教課:一種“初始化”自引用組的方法是使自引用匹配可選。

步驟4.5:了解出了什么問題

問題是,由于我們使自引用匹配可選,“計(jì)數(shù)器”可以“重置”回0,當(dāng)沒有足夠的。b讓我們仔細(xì)檢查一下在我們的模式的每一次迭代中發(fā)生了什么。aaaaabbb作為投入。

a a a a a b b b

# Initial state: Group 1 is "uninitialized".

_

a a a a a b b b

# 1st iteration: Group 1 couldn't match \1 since it was "uninitialized",

#? ? ? ? ? ? ? ? ? so it matched and captured just b

___

a a a a a b b b

# 2nd iteration: Group 1 matched \1b and captured bb

_____

a a a a a b b b

# 3rd iteration: Group 1 matched \1b and captured bbb

_

a a a a a b b b

# 4th iteration: Group 1 could still match \1, but not \1b,

#? (!!!)? ? ? ? ? ?so it matched and captured just b

___

a a a a a b b b

# 5th iteration: Group 1 matched \1b and captured bb

#

# No more a, + "loop" terminates

哈哈!在我們的第四次迭代中,我們?nèi)匀豢梢云ヅ鋅1但我們無法匹敵\1b!因?yàn)槲覀冊试S自引用匹配是可選的\1?,引擎回溯,并采取“不謝謝”選項(xiàng),然后允許我們匹配和捕獲僅僅。b!

但是,請注意,除了在第一次迭代時,您始終可以只匹配自引用。\1..當(dāng)然,這是顯而易見的,因?yàn)檫@就是我們在上一次迭代中捕獲的內(nèi)容,而且在我們的設(shè)置中,我們總是可以再次匹配它(例如,如果我們捕獲了bbb上一次,我們得到保證bbb,但可能有也可能沒有bbbb這一次)。

教課*提防回溯。regex引擎將執(zhí)行盡可能多的回溯,直到給定模式匹配為止。這可能會影響績效(即災(zāi)難性回溯)和/或正確性。

第五步:自救!

現(xiàn)在,“修復(fù)”應(yīng)該是顯而易見的:將可選的重復(fù)與占有性量詞也就是說,而不是簡單地?,使用?+相反(請記住,量化為占有式的重復(fù)不會倒退,即使這種“合作”可能會導(dǎo)致與總體模式的匹配)。

在非常非正式的條件下,這就是?+, ?和??說:

?+

(可選)“它不必在那里,”

(占有欲)“但如果它在那里,你必須接受它,而不是放手!”

?

(可選)“它不必在那里,”

(貪婪)“但如果是的話,你現(xiàn)在可以接受,”

(回溯)“但你以后可能會被要求放手!”

??

(可選)“它不必在那里,”

(不情愿)“即使是這樣,你也不必現(xiàn)在就接受它,”

(回溯)“但是你以后可能會被要求接受的!”

在我們的設(shè)計(jì)中,\1不會第一次出現(xiàn),但它會總在那之后的任何時候,我們總想匹配一下。因此,\1?+就能實(shí)現(xiàn)我們想要的。

$r5 = '/ ^ (?: a (?= a* (\1?+ b) ) )+ /x';

#? ? ? ? ? │? ? ?│? ? ? └──────┘ │ │

#? ? ? ? ? │? ? ?│? ? ? ? ? 1? ? │ │

#? ? ? ? ? │? ? ?└───────────────┘ │

#? ? ? ? ? │? ? ? ? ?lookahead? ? ?│

#? ? ? ? ? └───────────────────────┘

#? ? ? ? ? ? ?non-capturing group

現(xiàn)在輸出是:如ideone.com所見):

aaa 0

aaab 1 a|b? ? ? ? ? # Yay! Fixed!

aaaxb 0

xaaab 0

b 0

abbb 1 a|b

aabb 1 aa|bb

aaabbbbb 1 aaa|bbb

aaaaabbb 1 aaa|bbb? # Hurrahh!!!

哇!問題解決了!我們現(xiàn)在正確地計(jì)數(shù),就像我們想要的那樣!

教課學(xué)習(xí)貪婪、不情愿和占有性重復(fù)之間的區(qū)別。可選的-占有可以是一個強(qiáng)大的組合。

第6步:最后修飾

所以我們現(xiàn)在得到的是一個匹配的模式a一而再、再而三地a是匹配的,有一個對應(yīng)的b在第一組中捕獲。+在不再存在時終止a,或者如果斷言失敗是因?yàn)闆]有對應(yīng)的b為了a.

要完成這項(xiàng)工作,我們只需附加到我們的模式。\1 $..這現(xiàn)在是對第1組匹配的內(nèi)容的反向引用,后面是行錨的末尾。錨確保沒有額外的b在字符串中,換句話說,實(shí)際上我們有anbn.

下面是最后確定的模式,還有其他測試用例,包括一個長度為10,000個字符的測試用例:

$tests = array(

'aaa', 'aaab', 'aaaxb', 'xaaab', 'b', 'abbb', 'aabb', 'aaabbbbb', 'aaaaabbb',

'', 'ab', 'abb', 'aab', 'aaaabb', 'aaabbb', 'bbbaaa', 'ababab', 'abc',

str_repeat('a', 5000).str_repeat('b', 5000)

);

$r6 = '/ ^ (?: a (?= a* (\1?+ b) ) )+ \1 $ /x';

#? ? ? ? ? │? ? ?│? ? ? └──────┘ │ │

#? ? ? ? ? │? ? ?│? ? ? ? ? 1? ? │ │

#? ? ? ? ? │? ? ?└───────────────┘ │

#? ? ? ? ? │? ? ? ? ?lookahead? ? ?│

#? ? ? ? ? └───────────────────────┘

#? ? ? ? ? ? ?non-capturing group

它發(fā)現(xiàn)4個匹配:ab, aabb, aaabbb,以及a5000b5000..它需要只能在ideone.com上運(yùn)行0.06s.

步驟7:Java測試

因此,該模式在PHP中工作,但最終目標(biāo)是編寫一個在Java中工作的模式。

public static void main(String[] args) {

String aNbN = "(?x) (?:? a? (?= a* (\\1?+ b))? )+ \\1";

String[] tests = {

"",? ? ? // false

"ab",? ? // true

"abb",? ?// false

"aab",? ?// false

"aabb",? // true

"abab",? // false

"abc",? ?// false

repeat('a', 5000) + repeat('b', 4999), // false

repeat('a', 5000) + repeat('b', 5000), // true

repeat('a', 5000) + repeat('b', 5001), // false

};

for (String test : tests) {

System.out.printf("[%s]%n? %s%n%n", test, test.matches(aNbN));

}

}

static String repeat(char ch, int n) {

return new String(new char[n]).replace('\0', ch);

}

該模式如預(yù)期的那樣工作(如ideone.com所見).

現(xiàn)在我們得出結(jié)論.。

需要說的是a*在展望未來,確實(shí)是“主要的”+循環(huán)“,兩者都允許回溯。讀者被鼓勵確認(rèn)為什么這在正確性方面不是一個問題,為什么同時使這兩個所有格都能起作用(盡管也許將強(qiáng)制性和非強(qiáng)制性的所有量詞混合在同一個模式中可能會導(dǎo)致誤解)。

還應(yīng)該說,雖然它很整潔,但是有一個正則表達(dá)式可以匹配anbn這并不總是實(shí)踐中的“最佳”解決方案。一個更好的解決方案就是簡單的匹配^(a+)(b+)$,然后比較宿主編程語言中第1組和第2組捕獲的字符串的長度。

在PHP中,它可能如下所示(如ideone.com所示):

function is_anbn($s) {

return (preg_match('/^(a+)(b+)$/', $s, $groups)) &&

(strlen($groups[1]) == strlen($groups[2]));

}

本文的目的是不要讓讀者相信regex幾乎可以做任何事情;它顯然做不到,即使是它能做的事情,如果它帶來了一個更簡單的解決方案,至少應(yīng)該考慮部分委托給宿主語言。

如上面所提到的,這篇文章必須加上標(biāo)簽。[regex]對于堆棧溢出來說,它可能不僅僅是這樣。當(dāng)然,學(xué)習(xí)斷言、嵌套引用、擁有量詞等是有價值的,但更重要的一課也許是一個人可以嘗試解決問題的創(chuàng)造性過程、當(dāng)你受到各種約束時所需要的決心和辛勤工作,以及構(gòu)建工作解決方案的各個部分的系統(tǒng)組合,等等。

獎勵材料!PCRE遞歸模式!

由于我們確實(shí)提到了PHP,需要指出的是,PCRE支持遞歸模式和子程序。因此,以下模式適用于preg_match (如ideone.com所見):

$rRecursive = '/ ^ (a (?1)? b) $ /x';

目前,Java的regex不支持遞歸模式。

更多的獎勵材料!匹配anbncn !!

所以我們已經(jīng)看到了如何匹配anbn這是不定期的,但仍然是無上下文的,但我們也能匹配嗎?anbncn,哪一個甚至不是沒有上下文的?

答案當(dāng)然是,是!鼓勵讀者自己解決這一問題,但解決方案如下(與在ideone.com上用Java實(shí)現(xiàn)).

總結(jié)

以上是生活随笔為你收集整理的java正则表达式 n_如何将a^nb^n与Java正则表达式匹配?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。