アトミックグルヌプ化、たたは䞀歩䞋がらない

0.ふり


特定の王囜、特定の状態では、プログラマヌがいたした。 予想通り、圌の名前はむノァンでした。 圌は真の専門家であり、プログラマヌの䞉倧矎埳すべおを所有しおいたした。぀たり、圌は怠け者で、rog慢で、焊りたした。 その王囜で倧きな悲しみが起こりたした危機。 そしお、圌らは退職金なしでVanyaを仕事から远い出した。 ノァニャは長い間悲しみ、勇気を出し、䞖界䞭に履歎曞を送りたした。 どのくらいの時間、簡朔に、圌らはむンタビュヌのためにVanyaに電話をかけたした。 申請者には倚くの芁件がありたしたが、䞻なこずは、圌が正芏衚珟の良いコマンドを持っおいる必芁があるずいうこずでした。 むンタビュヌの1か月近く前です。準備はしたくありたせん。 真面目な人であるため、Ivanは詳现に準備するこずにしたした。 3週間ず3日間、圌はストヌブの䞊に暪たわり、Habrを読み、必然的に培底的に準備する方法を考えたした。 むンタビュヌの1日前。 Vanyushaは雇甚䞻を粟神的に呪いたした。雇甚䞻は面接をすぐに予定しおいるので、準備ができず、ストヌブから降りおビヌル瓶を枡し、収益のためにレックスの本を買いたした。 圌は圌が切断するたでそれを䜿い果たしお読んだ。 朝、私たちはハブラカトの䞋のこの本に、枕の䞊にいるかのように、バニュシャの眠い人盞が暪たわっおいるのを芋぀けたす。

1.再垰


むンタビュヌで、むノァンはそのような仕事を䞎えられたした。 括匧...内の匏ず䞀臎する正芏衚珟を蚘述したす。括匧内には、おそらく入れ子になった他の括匧内に倚くの匏がある堎合がありたす。 䟋チェヌン内
sin(2*pi/tan(.7+b*tanh(b/2)))+8*cos(b/4)
正芏衚珟は、ブラケットの最初のペアの内容ず䞀臎する芋぀ける必芁がありたす。
(2*pi/tan(.7+b*tanh(b/2)))
ただし、正芏衚珟は、ブラケットのバランスが取れおいないチェヌンの郚分ず䞀臎しないようにする必芁がありたす開いおいるブラケットは閉じず、逆にたったく開いおいないブラケット。 たずえば、チェヌンの凊理
(sin(b/2)
正芏衚珟は(b/2)芋぀ける必芁がありたす。1番目のブラケットは閉じないため、無芖したす。 そしお次のチェヌンで
2*pi)*(r*r
ここには「正しい」括匧のペアがないため、正芏衚珟は䜕も芋぀ける必芁はありたせん。 もう1぀の制限は、「空の」角かっこ()に䞀臎するこずを犁じおいるこずです。぀たり、角かっこ内に少なくずも䞀郚のコンテンツが必芁です。
぀たり、括匧で囲たれた「正しい」匏ず䞀臎する必芁がありたす。これには、括匧付きの郚分匏が含たれる堎合があり、空の括匧()正しいずは芋なされたせん。
むワンはおおよその衚珟を曞き、口ひげを振る
1目的の衚珟は括匧で囲たれたものです。
2角かっこ内には角かっこがないものがあり、すべおがシンプルです
(3.14 * R * R)
...たたは括匧内の䜕か
(2 * sin(pi/2))
やめお 埌者の堎合、括匧内には「括匧内の䜕か」ではなく、最初に「括匧なしの䜕か」 2 * sinがあり、それから「括匧内の䜕か」 (pi/2)たす。
そしお、括匧内に「括匧なしの䜕か」ず「括匧内の䜕か」が䜕床も発生する可胜性があるこずが明らかになりたす。
(2 * (a+8.5) * sin(pi/2) / (b - 1e-8)) 。
正芏衚珟蚀語で「角括匧なし」を蚭定するのは非垞に簡単です [^)(]+ 。遞択肢角括匧なし、たたは角括匧内の䜕かず「奜きなだけ」を蚭定する方法も簡単ですメタキャラクタヌ|および+ 「かっこ内の䜕か」ず正芏衚珟蚀語での蚘述方法
「カッコ内の䜕か」...「カッコ内の䜕か」...すでに出䌚った堎所...ああ、ここポむント
1目的の衚珟は括匧内の䜕かです。 この「括匧内の䜕か」ずは䜕ですか 探しおいる匏が括匧で囲たれおいる堎合、括匧で囲たれおいるのは...探しおいる匏です ナヌレカ
そのような文法はむノァンに起こりたす
怜玢匏:: =  {匏のない括匧|怜玢匏} + 
+は「1回以䞊」を意味したす。{a | b}は「aたたはb」を意味し、倪字の括匧は括匧自䜓の文字を意味し、
かっこなしの匏:: =かっこ以倖の任意の文字+
぀たり、目的の匏の定矩は再垰的です。 しかし、正芏衚珟の蚀語でそれを曞く方法は 正芏衚珟に自分自身を含めるこずはできたすか むノァンはそれは䞍可胜だず思っおいたでしょうが、あなたは忘れおいたした-圌は䞀ヶ月間䞀生懞呜準備をしおいたした 圌は、珟代の正芏衚珟゚ンゞンではこれが可胜であるこずを想起したした正芏衚珟内のどこでも
(?R)
正芏衚珟党䜓ぞのリンクを意味したす。 Ivanは次の正芏衚珟を蚘述したす/ xスむッチを䜿甚するず、改行を含むすべおの空癜文字が考慮されず、文字の埌のコメントも可胜になりたす。
/
\( #
(
[^)(]+ # --
| #
(?R) #
)+ # 1
\) #
/x


Ivanは、チェヌンのいく぀かの䟋を䜿甚しお正芏衚珟をチェックしたす良い、むンタビュヌでテストプログラムを実行できたす。オンラむンでドキュメントを読むこずはできたせん。
there are no parentheses here
(a + b)
sin((pi/180)*deg + theta)
1+(1+1/(1+1/(2+1/(1+1/(1+1/(4+1/(1+1/(1+1/(6+1/(1+1/(1+1/(8+1))))))))))))
sin)a - b(
sin(a - b(
sin(a * (b+1)
そしお、正芏衚珟はそれらすべおを期埅通りに凊理したす。 満足し、むノァンは面接官に決定を瀺したす。 ハッピヌ゚ンド、カヌテン しかし、なぜ蚘事の名前はそのたたですか??
むンタビュアヌは、次のチェヌンで正芏衚珟を怜玢する必芁がある堎合必芁な堎合を尋ねたす。
(you're gonna fail sonny unless you correct it (your regex)
読んで青ざめたバニュシャは、瞬きするこずなく、最初のブラケットがどこでも閉じおいないので、正芏衚珟はブラケットの2番目のペアを芋぀ける必芁があるず答えたす (your regex) 。 圌は確認するように求められたす。 Ivanはこのチェヌンを怜蚌スクリプトPerlに組み蟌みたす。
#!/usr/bin/perl -wl
use strict;

my $string = "(you're gonna fail sonny unless you correct it (your regex)";
print $string;

if ( $string =~ / \( ( [^)(]+ | (?R) )+ \) /x ) {
print "Match: $&";
} else {
print "Not matched!"
}


構文を確認した埌、Ivanはスクリプトを実行したす...そしお䜕も起こりたせん。スクリプトは「フリヌズ」しおいるようです。 圌はむ゚スでもノヌでもないず蚀っおいたす。 むノァンずむンタビュアヌは玄10秒間静かに芋たすが、この間、むノァンは淡いピンクから淡いピンクに倉わりたす。 しかし、圌は䜕を間違えたのですか?? この時点で、スクリプトが起動されたそしお䜕らかの理由でただ完了しおいないラップトップは、それたで静かに動䜜しおいたしたが、はっきりず隒ぎ始めたす。 面倒な長時間の䞀時停止を䞭断するために、むンタビュアヌはむノァンにお茶たたはコヌヒヌを提䟛したす。 「その間、あなたはただ䜕が間違っおいるのかを考えたす」ず圌は付け加えたす。 さらに30分が経過するず、Ivanはコヌヒヌ2杯ずレモン入り玅茶1杯を飲みたすが、スクリプトがなぜ神秘的に振る舞うのかはわかりたせん。 むンタビュアヌはむノァンず別れ、皇垝叞祭の人事郚の埓業員は「候補者はむンタビュヌの結果に応じお华䞋された」ず蚘しおいる。 そしお、ポむントに行きたす

2.壊滅的なロヌルバック


正芏衚珟Ivanはどうなりたしたか 正芏衚珟の仕組みを理解しおみたしょう
/ \( ( [^)(]+ | (?R) )+ \) /x
「運呜のない」チェヌン
(you're gonna fail sonny unless you correct it (your regex)
  1. 正芏衚珟の䞭括匧は、チェヌン内のブラケットず䞀臎したす
  2. [^)(]+䞀臎you're gonna fail sonny unless you correct it 、 you're gonna fail sonny unless you correct it 、「食べる」こずができない開始ブラケットに「静止」しyou're gonna fail sonny unless you correct itなりたす
  3. 代替... | ...は、貪欲な量指定子+ずずもに䜿甚されるため、正芏衚珟゚ンゞンは... | ...を再床怜玢しようずしたす。 最初の分岐[^)(]+開始ブラケットを芋た盎埌の遞択肢「䞀臎できたせん」ず蚀う
  4. ゚ンゞンは2番目の遞択肢(?R)たす。 これは最初は正芏衚珟党䜓です。 そしお、チェヌン内に残っおい(your regex) 。 すべおが単玔ですブラケット正芏衚珟内はブラケットず䞀臎チェヌン内、 [^)(]+ your regexず䞀臎[^)(]+代替のその他の出珟... | ...゚ンゞンはチェヌンの残りの郚分では怜出したせん。かっこなし」、開き括匧、゚ンゞンは正芏衚珟の閉じ括匧に移動したす。チェヌン内の括匧ず䞀臎したす。
  5. さお、゚ンゞンは䜕ずか元のチェヌン(your regex)郚分(?R)
  6. チェヌンでは、文字が残っおいたせんでした。 ... | ...+の量指定子は貪欲で、正芏衚珟゚ンゞンは別の代替... | ...を芋぀けようずしたすが、成功したせんチェヌンの残りの空の郚分では、䜕も芋぀かりたせんブラケット、ブランチ(?R)を開始できる開始ブラケットなし
  7. したがっお、もう1぀の遞択肢は芋぀かりたせん。 たあ、すべおの欲は境界を持たなければなりたせん。 ゚ンゞンは「コンテンツ」であり、チェヌン内ですでに2぀の遞択肢が芋぀かっおおり、正芏衚珟の次の郚分に進みたす。 これは右倧括匧です。 ただし、チェヌンにはブラケットはありたせん。チェヌンでは、珟時点ではたったく空です。正芏衚珟の以前の郚分は既にマりント解陀されおいたす。 開き括匧を正芏衚珟ず䞀臎させるものは䜕もありたせん。
  8. 正芏衚珟゚ンゞンをさらに進化させるものは䜕ですか 降䌏し、䞀臎がないず蚀いたすか たさか。 圌は、数量詞[^)(]+を䜿甚した最埌の衚珟が貪欲であり、正芏衚珟の次の郚分に䜕も残さずに「食べ過ぎ」た可胜性があるこずを芚えおいたす。正芏衚珟゚ンゞンはロヌルバックしたす。
  9. ゚ンゞンは、前回[^)(]+ your regexチェヌンを「食べた」こずを思い出したした。 [^)(]+匷制的に1文字xを正芏衚珟の次の郚分[^)(]+ 「䞎え」たす。぀たり、チェヌンは残りたす x) 正芏衚珟では、代替... | ...+
  10. K. +は貪欲であるため、゚ンゞンは別の1぀の代替... | ...を芋぀けようずしたす。代替の最初のブランチ[^)(]+ 、 x蚘号は玠晎らしく䞀臎したす。チェヌンに残っおいたす。

これは非垞に長い間続けるこずができたすが、実際には、問題がすでに衚面化しおいたす。これは悪の根源であり、正芏衚珟の欠陥です。 チェヌン内で、人間の芳点から括匧なしの1぀の䞍可分なトヌクンである正芏衚珟゚ンゞンで、正芏衚珟゚ンゞンは2぀のトヌクンを怜出したした正芏衚珟[^)(]+の「異なるコピヌ」に分散されたyour regeおよびx゜ヌス正芏衚珟
/ \( ( [^)(]+ | (?R) )+ \) /x
すべおが「䜙分」で、チェヌン内の蚘号「」たたは「」の存圚を必芁ずするものすべおそしお、正芏衚珟チェヌンには明らかにこれらの蚘号がありたせん、残っおいるものはすべお
/ ( [^)(]+ )+ /x
そしお、ここで問題はさらに明癜になりたす。 結局、 your regexはyour regex 1トヌクンずしお、正芏衚珟ずx 2トヌクンずしお、そしお、 youずr regexずしお、3、4、...、たたは10個の個別トヌクンずしおプレむできたす。 your regexチェヌンをトヌクンに分割your regexオプションの数は膚倧です。 正芏衚珟/ ( [^)(]+ )+ /xは、必芁に応じお、これらのオプションをすべお列挙するこずを意味したす。 テストチェヌンをチェックするずきにすぐにIvanがこの問題に気付かなかったのはなぜですか その堎合、通垞の運がありたしたチェヌンを壊すためのオプションの数は膚倧でしたが、砎壊の最初のバリ゚ヌション[^] +、貪欲で、党䜓ずしお括匧なしでテキスト党䜓をキャプチャするずきが成功したこずが刀明したため、正芏衚珟゚ンゞンはロヌルバックする必芁がありたせんでした 。 むンタビュアヌによっお䞎えられたチェヌンの堎合、長い文字列をトヌクンに分割する1番目、2番目、100,000,000番目のオプションのいずれも䞀臎しなかったため、すべおが悪化したした。そうではありたせんでした。 そのため、埌者の堎合、正芏衚珟゚ンゞンはロヌルバックし、たすたす倚くの分割オプションを詊行したすが、劥圓な時間内に䞀臎を芋぀けるこずはありたせん。 これは壊滅的なプルバックず呌ばれたす。

3.原子のグルヌプ化


この問題を防ぐこずはできたすか はい、非垞に簡単です。 問題は、「愚かな」正芏衚珟゚ンゞンがギリシャ語のカレンダヌにロヌルバックされるのに察し、人が理解するのは䞀芋しかないこずです。ロヌルバックは圹に立たないこずです。 your regex およびチェヌンの前の郚分を郚分に分割するこずは、䞍足しおいる閉じ括匧を芋぀けるのに圹立ちたせん。 正芏衚珟゚ンゞンに䌝える方法がありたす「これが完党䞀臎の欠劂に぀ながる堎合でも、この堎所でロヌルバックを詊みないでください。」
(?> .....)
これは「アトミックグルヌプ化」ず呌ばれ、おおよそ「 (?>ず)間の正芏衚珟の郚分では、ロヌルバックは犁止されおいたす」ずいう意味(?> 。 たたは、より正確には、別の方法で。 (?>X) Xは正芏衚珟A(?>X)Bより倧きい正芏衚珟A(?>X)B䞀郚ずしたすAずBも䜕らかの正芏衚珟です。 文字列abをこの倧きな正芏衚珟の入力に送信したす。ここで、aずbは単䞀の文字ではなく、文字のチェヌンです。 倧きい正芏衚珟の最初の郚分Aが、チェヌンaの察応「otmatchil」をすでに芋぀けたずしたす。 正芏衚珟゚ンゞンは正芏衚珟> Xに進み、凊理されたチェヌンでは、文字ポむンタヌはチェヌンaの盎埌およびbの盎前に続きたす。 この堎合、アトミックグルヌプ化> Xは、チェヌンbが絶察に独立した独立した正芏衚珟Xに適甚されたかのように機胜したす。 Xは「知らない」ので、圌の埌に他の正芏衚珟Bがあるかどうか、Bが䜕かをプレむできるかどうかは気にしたせん。 Xは、圌以倖にrexeが存圚しないかのように動䜜したす。 特に、Xに貪欲な量指定子が含たれおいる堎合
(?> [^)(]+ )
アトミックグルヌプは、この「貪欲な」郚分のロヌルバックを蚱可したせん。 your regexチェヌン党䜓をすぐにキャプチャした堎合は、1぀前のステップではなく、そうしおyour regex 
括匧内のテキストを芋぀けるために正芏衚珟を倉曎するず、問題が解決したす。
/ \( (?> [^)(]+ | (?R) )+ \) /x

蚘事Super-greedy quantifiersで 、数量詞++、* +などを調べたした。super-greedy数量詞はアトミックグルヌプの特殊なケヌスであるこずがわかりたす。 たた、元の正芏衚珟の量指定子を超欲匵りにするこずで、同じ効果を埗るこずができたす壊滅的なロヌルバックを取り陀きたす。
/ \( ( [^)(]++ | (?R) )+ \) /x
たたはそれ以䞊
/ \( ( [^)(]++ | (?R) )++ \) /x

それが物語の終わりであり、誰が聞いたのか...著者に悲したせおください。著者は、蚘事を曞く前に、説明が非垞に長く䞍完党であるこずさえ考えられたせんでした。 しかし、誰かが䜕かを理解し、バニャの経隓を繰り返さなかった堎合、それはすでに䜕か䟡倀がありたす。

Source: https://habr.com/ru/post/J56765/


All Articles