25
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

JavaScript全置換(正規表現使わない)の速度比較

Last updated at Posted at 2017-05-14

2017年05月15日 記入

プログラミングのテクニックサイトで全置換は正規表現とか書かないで欲しい

JavaScriptのreplaceは、先頭文字だけしか置換でないので、全置換のやり方は、replace(/文字/g)みたいに、正規表現をつかいます。

というようにかかれている場合があります。[JavaScript 全置換]とかで検索すると多く出てくるので、ため息まじりになります。

プログラミングのテクニックとしてそれはよくないです。文字列置換と正規表現による一致をみて置換するのとは処理が違います。

正規表現はプログラミングでは複雑さがまし、また可読性も低いのであまり使わないようにしています。ただ、正規表現を使うようが望ましくなる場面では使います。使い所を選ぶプログラミングの機能です。

そして、単なる文字列置換に正規表現を使うのは実に望ましくありません。置換元の文字に正規表現が含まれていたら、困るでしょう。

例えば、「*.co.jp」という文字列を「*.com」に純粋な文字として置換したいときに、正規表現文字列置換では簡単ではなくなるので応用が効かなくなるのでよくないのです。

全置換は、こんなコードがいいのかな

ということで、自分は次のようなコードを書いていました。

  var replaceAll1 = function(str, before, after) {
    var result = str
    do {
      str = result;
      result = str.replace(before, after);
    } while (str !== result);
      return result;
  };

これは、replaceを文字が変換されなくなるまで繰り返すという実装です。行数はほどほど必要ですがロジックとしてはシンプルです。

正規表現置換のreplace(/文字/g)よりは行数が必要ですが、関数の中身はカプセル化されているから数行程度の行数が増えてもよいのです。

こっちのコードの方がいいのかな

ですが、正規表現とともによく掲載されているのは次のコードでした。

  var replaceAll2 = function(str, before, after) {
    return str.split(before).join(after);
  };

え....splitしてjoinするんだ...

ということで、replaceAll1の方が順当と思ったんですが、replaceAll2も、いいのかな、どちらもいいけど、ロジック的にシンプルなreplaceApp1の方が速いんじゃないの。と思い、ベンチマークをとることにしました。

HTML上でベンチマーク

ベンチマークのとり方は、こちらを参考にさせていただきました。
JavaScript:処理時間計測方法 | 覚え書き.com

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <script>

  var replaceAll1 = function(str, before, after) {
    var result = str
    do {
      str = result;
      result = str.replace(before, after);
    } while (str !== result);
      return result;
  };

  var replaceAll2 = function(str, before, after) {
    return str.split(before).join(after);
  };

var benchMark = function (replaceAll) {
  var startTime = new Date();

    for (var i = 1; i <= 10000; i++) {
      var result = replaceAll(
        new Array(10).join('abc123abc123abc'), 'abc', '123');
      if (result !== new Array(10).join('123123123123123')) {
        alert('error');
        break;
      }
    }

  var endTime = new Date();
  return endTime - startTime;
};

//startTime から endTime までの処理時間をミリ秒で出力。
alert(benchMark(replaceAll1) + "ms");
alert(benchMark(replaceAll2) + "ms");

    </script>
  </head>
  <body>
    <!-- page content -->
  </body>
</html>

これで測ると、圧倒的にreplaceAll2が速かったです。
実行速度にぶれはあるので掲載しませんが、確実に速いです。
やりたい人は、ループ数をご自分でいろいろ変えてみてください。

環境はChromeです。

そういうもんなんですね....知らなかった。

シンプルかつ、高速なのは、 split して join ですね。

ということで、
replaceAll2の書き方をおすすめします。

現場からは以上です。

追記 2021年07月15日 String.prototype.replaceAll

現在は主要なブラウザは次のメソッドが存在しているのでそちらを使うのがよいでしょう。

String.prototype.replaceAll() - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll

25
17
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?