2011-10-21 11 views
2

Javascriptを使用して中程度に複雑な文法を解析しています。正規表現を使用して数字などのトークンを一致させたいと考えています。Javascript RegExpは、検索せずに正確な文字列オフセットで一致することはできますか?

文法を含む文字列、文字列内の数字とオフセットを表す正規表現を指定すると、正規表現がそのオフセットの文字列と正確に一致するかどうかを調べたいと思います。

lastIndexを設定し、RegExp.execを呼び出して、結果の一致のインデックスプロパティを調べて、期待されるオフセットで一致が発生したかどうかを調べることができますが、これは非常に効率的ではありません開始オフセットで一致を見つける。

Javascript仕様では、「Patternは内部プロシージャ値を評価(コンパイル)します。RegExp.prototype.execはこのプロシージャをStringおよびString内のオフセットに適用して、パターンが開始と一致するかどうかを判断しますストリング内の正確にそのオフセットで。

これは私が欲しいものですが、この内部機能にアクセスする方法はないようです。誰か知っていますか?

P.S.私は現在、入力文字列をトークンの配列に分割することによってこの問題を回避していますが、そうしたくないです。

+0

私はあなたを正しく理解しているかわかりませんが、代わりに 'str.substring(index)'を使って正規表現とマッチしてインデックス '0'でマッチするかどうか確認できませんか? – pimvdb

+0

@pimvdb - Robへの私の答えを参照してください – arx

答えて

2

検索開始位置を設定することができれば、実際の不一致で終了するアサーションの末尾アンカーの
を利用できる場合があります。


は、その開始位置が文字列の最後に来るときに唯一一致しないことを受け入れる必要があります。

次に、キャプチャバッファの長さをチェックするプロセスをポストします。これは正規表現に依存しますが、
ですが、キャプチャバッファの長さがゼロの場合は失敗する可能性があります。

例:
(\d{6} | (?!$))又は((?:any subexpression) | (?!$))

(開始位置が文字列の最後にある、又は
文字列が空でない場合)、これは常に一致します。

アウトカム
- 一致しません:文字列が空である、または位置を開始することは、文字列の末尾にあります。
- 一致:時間の99.999%。キャプチャバッファの長さが0の場合(つまり: '')、交替の左側にある
のいずれかが失敗したか、または何もキャプチャしていない、正規表現に依存します。

開始位置は注意しますが、正規表現の静的な長さの一致は、数量化ツールで制御するのが難しい(不可能ではない)ことがあります。そのおそらくより多くの
オープンエンドの量指定子の場合に部分文字列の正規表現を使用することは妥当です。

+0

ありがとう、いいアイデアです。 – arx

7

私は徹底的に効率的な方法、おそらくテストした、JSPerfを参照してください。~20000文字、~1000000文字。私は、英数字からなるランダムな文字列を生成する関数を作成しました。この関数を1回実行すると、指定されたオフセットで長さ10の文字列と一致するように、RegExpパターンが作成されます。

テスト済みの場合if(..)の条件が真であるとき、パターンがで発見されたindexオフセット):

var string = "...about 20000 characters: A-Z a-z 0-9..."; 
var regexp = /abcdef1324/g; 
var regexpSubstr = /^abcdefg1234/; 
var index = 10000; 

/*1*/ if (regexpSubstr.exec(string.substr(index,10))) ; 
/*2*/ regexp.lastIndex = index; 
     var found = regexp.exec(string); 
     if (found && found.length + index == regexp.lastIndex) ; 

/*3*/ if (regexpSubstr.test(string.substr(index,10))) ; 
/*4*/ // Only when the RegExp matches a fixed number of characters 
     regexp.lastIndex = index; 
     if (regexp.test(string) && regexp.lastIndex == index + 10) ; 

ケース1ケース彼らはチェックしているので、3は、等価です部分文字列が/^abcdef1234/パターンと一致するかどうか(選択した部分文字列は "abc..etc"で始まりますか?)

ケース2及びケース4.lastIndex方法使用:パターンが見つかったかどうかを所望のオフセット
  チェックする正規表現の.lastIndexプロパティを設定
  を。
    3.  見つかったパターンがオフセットindexに配置されているかどうかを確認します。
これらのメソッドでは、グローバルフラグを有効にするには正規表現が必要です。

非常に大きな文字列では、方法4(lastIndex + test)は、オフセット時の一致が発生するとproved to be most efficientです。しかしながら、方法4は、一致パターンが所定の固定サイズを有することを要求する。所定の位置で一致が生じると、方法3(substr + test)は4よりわずかに遅い。ただし、大きな文字列で一致が見つからない場合、方法3は方法4よりもsignificantly fasterです。一致が見つからない場合、方法1と方法3はequally fastと思われます。

RegExpオブジェクトのメソッド
.exec.testよりも効率的ではないようです。 matchメソッドは、.lastIndexプロパティに関係なく、すべての一致を検索しようとするため、このケースには適していません。もう1つの可能なRegExp関数は、.search関数です。これは、以前に示したメソッドと比較して、大きな文字列の方がはるかに遅くなります。

+0

私は、アドホックな部分文字列をたくさん作成することなく、入力全体を1回のパスでスキャンしたいと思います。これは確かに可能ですが、Javascriptで効率的に実行でき、正規表現を使用できるかどうかはわかりません。実際には、正規表現でも多くの特別な部分文字列が作成されるため、おそらくこれが最適な解決策です。 – arx

+0

@arx開始オフセットが '123354 ...'であることがわかっている場合は、RegExp検索クエリでオフセット0〜123354 ...を含めるのではなく、位置123354 ....から部分文字列を取り出す方が効率的です。 –

+0

これは問題ではありません。正規表現のlastIndexプロパティを使用して、123354で検索を開始できます。一致する文字列が見つからない場合は、文字列の残りの部分を検索しないようにしたいのですが、問題も解決しますが、新しい文字列を作成するという代償を払ってください。しかし、私が上で述べたように、これは妥当な価格だと思っています。 – arx

関連する問題