3

1つの問題:

文字列(str)を処理して、括弧で囲まれた数字(と一致する)が配列( )rgxの適切な場所から取得された値に置き換えられるようにします。sub

var rgx = /\((\d+)\)/,
    str = "this (0) a (1) sentence",
    sub = [
            "is",
            "test"
        ],
    result;

上で宣言された変数が与えられたresult場合、は「これはテスト文です」である必要があります。

2つの解決策:

これは動作します:

var mch,
    parsed = '',
    remainder = str;
while (mch = rgx.exec(remainder)) { // Not JSLint approved.
    parsed += remainder.substring(0, mch.index) + sub[mch[1]];
    remainder = remainder.substring(mch.index + mch[0].length);
}
result = (parsed) ? parsed + remainder : str;

しかし、次のコードの方が速いと思いました。変数が少なく、はるかに簡潔で、無名関数式(またはラムダ)を使用します。

result = str.replace(rgx, function() {
    return sub[arguments[1]];
});

これも機能しますが、速度については間違っていました。 Chromeでは、驚くほど遅くなります(〜50%、前回チェックしたとき)

..。

3つの質問:

  1. このプロセスがChromeで遅く、(たとえば)Firefoxで速く見えるのはなぜですか?
  2. より大きな文字列または配列が与えられた場合、メソッドがループreplace()と比較して高速になる可能性はありますか?そうでない場合、コードゴルフwhile()以外のメリットは何ですか?
  3. このプロセスを最適化して、機能的な2番目のアプローチと同じくらい効率的かつ手間のかからない方法はありますか

これらのプロセスの背後で何が起こっているのかについての洞察を歓迎します。

..。

[記録のために:「ラムダ」および/または「機能的」という言葉の使用について声をかけられてうれしいです。私はまだ概念について学んでいるので、私が話していることを正確に知っていると思い込まないでください。ここで用語を誤用している場合は、遠慮なく訂正してください。]

4

2 に答える 2

3

このプロセスがChromeで遅く、(たとえば)Firefoxで速く見えるのはなぜですか?

(非ネイティブの)関数を呼び出さなければならないため、コストがかかります。Firefoxのエンジンは、ルックアップを認識してインライン化することにより、それを最適化できる可能性があります。

より大きな文字列または配列が与えられた場合、replace()メソッドがwhile()ループと比較して高速になる可能性はありますか?

はい、文字列の連結と割り当てを少なくする必要があります。また、あなたが言ったように、初期化する変数も少なくて済みます。それでも、私の仮定を証明するためにそれをテストすることしかできません(そして他のスニペットについてはhttp://jsperf.com/match-and-substitute/4も見てください-たとえば、Operaがラムダ置換2を最適化するのを見ることができますが、そうではありません使用arguments)。

そうでない場合、コードゴルフ以外のメリットは何ですか?

コードゴルフは正しい言葉ではないと思います。ソフトウェアの品質とは、読みやすさとわかりやすさのことであり、関数型コードの簡潔さと優雅さ(主観的ですが)がこのアプローチを使用する理由です(実際、私は、との置き換えや再連結を見たことがありませんexecsubstring

このプロセスを最適化して、機能的な2番目のアプローチと同じくらい効率的かつ手間のかからない方法はありますか?

remainderその変数は必要ありません。にrgxは、自動的に一致を進めるlastIndexプロパティstrがあります。

于 2013-03-17T20:28:43.733 に答える
2

非グローバル正規表現で使用するときに余分な作業()を実行しているため、のwhileループは本来よりもわずかに遅くなります。すべての一致をループする必要がある場合は、グローバル正規表現(フラグが有効)でループを使用する必要があります。このようにして、文字列の処理された部分をトリミングする余分な作業を回避します。exec()substringexec()whileg

var rgR = /\((\d+)\)/g;
var mch,
    result = '',
    lastAppend = 0;

while ((mch = rgR.exec(str)) !== null) {
    result += str.substring(lastAppend, mch.index) + sub[mch[1]];
    lastAppend = rgR.lastIndex;
}
result += str.substring(lastAppend);

ただし、この要因によって、異なるブラウザ間のパフォーマンスの違いが妨げられることはありません。

パフォーマンスの違いは、ブラウザの実装に起因しているようです。実装に不慣れなため、違いがどこから来ているのか答えることができません。

力の面で、exec()そしてreplace()同じ力を持っています。これには、からの戻り値を使用しない場合も含まれますreplace()例1例2

replace()関数によって返される値を使用している場合(つまり、無名関数で実際の置換を行っている場合while)、メソッドはループよりも読みやすくなります(意図が明確になります)。また、置き換えられた文字列を自分で再構築する必要はありません。これは、よりも優先される場所です。(これが質問2の2番目の部分に答えることを願っています)。exec() replaceexec()

exec()交換以外の目的で使用されることを想像します(このような非常に特殊な場合を除く)。交換は、可能であれば、で行う必要がありますreplace()

最適化が必要なのは、実際の入力でパフォーマンスが大幅に低下する場合のみです。2つの異なるブラウザ間でパフォーマンスが矛盾しているため、可能な2つのオプションのみがすでに分析されているため、表示する最適化はありません。これは将来変更される可能性がありますが、現時点では、ブラウザ全体で最もパフォーマンスの低いものを選択して使用できます。

于 2013-03-17T21:10:38.403 に答える