2016-02-05 3 views
6

javascriptで以下のコードを実行しようとすると、設計が不適切な正規表現のために無限ループする致命的なバックトラッキングが原因でブラウザがハングします。私は別の発現またはこの問題を回避するための方法のいずれかが必要になります。正規表現を "致命的なバックトラッキング"にしないようにするにはどうすればよいですか?

string temp = "Testing robustness {parent-area-identifier Some text in between the tokens {parent-area-label}"; 
var strRegExp = new RegExp(/[{](?:[^{}]+|[{][^{}]*[}])*[}]/g); 
var arrMatch = temp.match(strRegExp); 
+2

何をすべきか? – Akxe

+0

ブラウザをハングして適切な結果を返してはいけません。このケースでは、 "{parent-area-label}"と一致し、以前のトークンを無視する必要があります。 –

+0

http://regexr.com/でテキストが書かれていて、正しく動作するようです....更新:例でチェックしてタイムアウトが報告されました – maborg

答えて

5

あなたの正規表現は、よりバランスの取れたペアがネストされていますが、レベルが1つしかないバランスのとれたマッチに一致するように見えます。この正規表現は、不正な入力に掛けなくても、その行います

{[^{}]*(?:{[^{}]*}[^{}]*)*} 

これはJeffrey Friedl'sアンロールループ技術の一例です。最初の[^{}]*にブレース以外の文字がなくなると、次の部分は単純なネストされていないブレースのペアとのマッチングを試み、次に中括弧以外のものを探します。その部分は、複数のネストされたブレースのペア(ただし、すべて同じレベル)を許可するためにループされています。

これは壊滅的なバックトラック(ネストされた量指定子、オプションのすべて)に対してさらに脆弱に見えるかもしれませんが、マッチが不可能であってもバックトラックする必要がないため動作します。

括弧をエスケープする必要はありませんが、限定子の一部として使用しているように見えない限りは、エスケープする必要はありません。 (いくつかのフレーバーでは、左のブレースをエスケープする必要がありますが、JavaScriptは使用しません)

また、未知の深さにネストされた中カッコをマッチングさせたい場合、あなたは不運です。いくつかの味はそれを管理することができますが、JavaScriptはあまりにも限られています。

+0

この構造体がはるかに優れていても、特に "例"文字列の最後にコンテンツを追加すると、 "正常"(つまり致命的ではない) https://regex101.com/r/zW9nG6/1を参照してください)。アトミックグループのエミュレーションを使用してそれを防ぐことができます:https://regex101.com/r/zW9nG6/2 –

+0

うわー!!私はあなたがそれを整理していると思う:)完璧に動作し、私はまだ答えとしてマークする前に徹底的にテストしています。 –

1

あなたは中括弧なしでエリアを選択したい場合は、このメソッドを使用するようにしてください:

var temp = "{=rankedArea?metricType=3902&area={parent-area-identifier}:AdministrativeWard} {=rankedArea?metricType=3902&area={parent-area-identifier}:{ward-type-identifier}} {district-short-label} adfasdfasdfasdf asdf asdf asdf asdf {child-area-short-label} asdf asdf asdf {authority-area-short-label} asdfasdfasdfasdf asdf asdfasdfasdfasdf asdf{=compare?metricType=3343&greater=greater than&equal=equal to&less=less than} asdfasdfasdfasdf asdf asdfasdfasdfasdf asdf{=countAreas?area={ancestor-2-identifier}:{ancestor-1-type-identifier}} asdfasdfasdfasdf asdf asdfasdfasdfasdf asdf{=equivalent?metricDimension=[218][218_Number][Specificethnicity][Ethnicity_AsianorAsianBritish]} asdfasdfasdfasdf asdf asdfasdfasdfasdf asdf asdfasdfasdfasdf asdf asdfasdfasdfasdf asdf {=metricTypeMetadata?metricType=3341&returnValue=source} asdfasdfasdfasdf asdf asdfasdfasdfasdf asdf{=value?metricType=3284} asdfasdfasdfasdf asdf asdfasdfasdfasdf asdf{=percent?metricType=518} asdfasdfasdfasdf asdf asdfasdfasdfasdf asdf{=rank?metricType=3287} asdfasdfasdfasdf asdf asdfasdfasdfasdf asdf{=rankedArea?metricType=3286} asdfasdfasdfasdf asdf"; 
var strRegExp = new RegExp(/{(?:[^{}]+|{[^{}]*})*}/g); 
var arrMatch = temp.match(strRegExp); 
console.log(arrMatch.length); 
console.log(arrMatch); 

結果:

13 
["{=rankedArea?metricType=3902&area={parent-area-identifier}:AdministrativeWard}", 
"{=rankedArea?metricType=3902&area={parent-area-identifier}:{ward-type-identifier}}", 
"{district-short-label}", 
"{child-area-short-label}", 
"{authority-area-short-label}", 
"{=compare?metricType=3343&greater=greater than&equal=equal to&less=less than}", 
"{=countAreas?area={ancestor-2-identifier}:{ancestor-1-type-identifier}}", 
"{=equivalent?metricDimension=[218][218_Number][Specificethnicity][Ethnicity_AsianorAsianBritish]}", 
"{=metricTypeMetadata?metricType=3341&returnValue=source}", "{=value?metricType=3284}", 
"{=percent?metricType=518}", 
"{=rank?metricType=3287}", 
"{=rankedArea?metricType=3286}"] 

このアルゴリズムが間違っていると、速く動作します。より多くのテストケースを提供してください。

+0

私は入れ子トークンを持っています。あなたのパターンはその場合には機能しません。これをチェックしてください:http://regexr.com/3co1m –

+0

Nishit、私は自分のソリューションを更新しました。今は正常に動作するはずです。正規表現は問題ありません。ちょっと修正する必要があります。 –

+0

あなたの正規表現は現在のOPと同じで、入力が不正な場合にも同じ問題が発生します。テスト文字列( ':AdministrativeWard'の後ろ)にある2番目の閉じ括弧を削除してテストします。私はRegexBuddyで壊滅的なバックトラッキングエラーが発生します。 –

関連する問題