【JavaScript】replace()メソッドの使い方と応用【文字列を置換する】

プログラミング

こちらのアプリ↓を作るときにJavaScriptreplace()メソッド周りで詰まったので、忘備録を書きます。

任意の文字列を一気に置換するツール | 俺のテキスト置換ツール
任意の文字列を一気に置換するツールです。指定した文字列にはハイライトがつくので、特定の文字列を探すのにも使えます。面倒くさい書き換え作業もサクッと終わります。

replace()メソッドの基本的な使い方

まず、JavaScriptのreplace()メソッドは、置換したいテキストに対して

replace(’置換したい文字列’,’置換後の文字列’)

みたいに使います。

記述例

たとえばこんな感じ。

//元のテキスト
let text = 'おはようございます。今日はいい天気ですね。';

//replace()を使って「おはようございます」を「こんにちは」に置換する。
text = text.replace('おはようございます', 'こんにちは');

//console.logで出力を確認する。
console.log(text);
//結果:こんにちは。今日はいい天気ですね。

おはようございます」が「こんにちは」置換されるはずです。

しかし、一か所しか置換されない!

しかし、上記の書き方だと少し問題があります。

一か所しか置換されないのです。

たとえば、

//元のテキスト
let text = 'しんぶんし。下から読んでも、しんぶんし。';

元のテキストに置換したい文字列が2か所以上ある場合…

let text = 'しんぶんし。下から読んでも、しんぶんし。';

text = text.replace('しんぶんし', 'イカとカイ');

console.log(text);
//結果:イカとカイ。下から読んでも、しんぶんし。

先ほどの書き方だと、最初の「しんぶんし」しか置換されません。

どちらの「しんぶんし」も「イカとカイ」に置換したい!

//gで囲む。

結論から言えば、「正規表現のgオプション」を使うと解決します。

やり方は、置換したい文字列を「 」の代わりに「/ /g」で囲むだけ。

let text = 'しんぶんし。下から読んでも、しんぶんし。';

text = text.replace(/しんぶんし/g, 'イカとカイ');

console.log(text);
//結果:イカとカイ。下から読んでも、イカとカイ。

これで全ての「しんぶんし」が「イカとカイ」に置換できました!

replaceAll()でもできる

ちなみに、近年追加されたreplaceAll()メソッドでも上手くいきます。

let text = 'しんぶんし。下から読んでも、しんぶんし。';

text = text.replaceAll('しんぶんし', 'イカとカイ');

console.log(text);
//結果:イカとカイ。下から読んでも、イカとカイ。
String.prototype.replaceAll() - JavaScript | MDN
replaceAll() メソッドは、pattern にマッチしたすべての文字列を replacement で置き換えた新しい文字列を返します。pattern は文字列または RegExp を指定することができ、replacement は文字列または各マッチに対して呼び出される関数を指定することができます。

※対応するブラウザには注意

"replaceAll" | Can I use... Support tables for HTML5, CSS3, etc
"Can I use" provides up-to-date browser support tables for support of front-end web technologies on desktop and mobile web browsers.

変数で置換したい文字列を指定したい。

さて。

ここまでは、「置換したい文字列」も「置換後の文字列」も直接replace()メソッドの中に文字列を書き込んでいました。

replace(/置換したい文字列/g, ’置換後の文字列’)

これを変数で指定したくなってきます。

しかし…

let text = 'しんぶんし。下から読んでも、しんぶんし。';
let before_word = 'しんぶんし'
let after_word = 'イカとカイ'

text = text.replace(/before_word/g, after_word);

こんな感じ↑に馬鹿正直に変数に置き換えて書いてもダメです。

置換したい文字列が”before_wordそのもの“になるので、上手くいきません。

では、どうするか。

RegExp オブジェクトのコンストラクター関数を呼び出す。

コンストラクター関数というやつを使います。

つまり、こうやって書けばOK!

text = text.replace(new RegExp(before_word, "g"), after_word);

これで

//元のテキスト
let text = 'しんぶんし。下から読んでも、しんぶんし。';
let before_word = 'しんぶんし'
let after_word = 'イカとカイ'

text = text.replace(new RegExp(before_word, "g"), after_word);

console.log(text);
//結果:イカとカイ。下から読んでも、イカとカイ。

変数を使ってreplace()メソッドを使えました!

しかし…

これで大体上手くいくはずです。

しかし、メタ文字(正規表現で使用する特殊文字)が誤った形で「置換したい文字列」に含まれていた場合にエラーになります。

たとえば、半角の括弧 → (だけとかです。

【保存版】正規表現でエスケープが必要な文字一覧表 - Qiita
エスケープ前 エスケープ後 注意点 \ \ エスケープを行う文字そのものなので、\ だけの記述はできません。\ にマッチングさせたい場合は \ と記述してください。 * \* + \+ . \. ...

対策1:先に正規表現でエスケープが必要な文字を置換する。

対策の一つ目は最初から正規表現を封じる方法。

やり方は、replace()メソッドもう一つ使います。

before_word = before_word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')

前もって正規表現をエスケープさせてエラーになるのを防ぐわけです。

let text = 'しんぶんし。下から読んでも、しんぶんし。';
let before_word = '(しんぶんし'
let after_word = 'イカとカイ'

before_word = before_word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
text = text.replace(new RegExp(before_word, "g"), after_word);

console.log(text);
//結果:しんぶんし。下から読んでも、しんぶんし。

つまりこうです。

これで「(しんぶんし」の「(」でエラーにならずに済みます。

対策2:エラーになったときだけ対応する。

でも、できれば正規表現も使いたいよ…。

そんな時は、try-catch文を使ってみます。

try {
    text = text.replace(new RegExp(before_word, "g"), after_word);
} catch (e) {
    before_word = before_word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    text = text.replace(new RegExp(before_word, "g"), after_word);
};

try{}の中身が通常の処理、catch(e){}の中身がエラー時の処理です。

エラー時だけ正規表現をエスケープさせるわけです。

let text = 'しんぶんし。下から読んでも、しんぶんし。';
let before_word = '(しん.ん.)'
let after_word = '!!$1!!'

try {
    text = text.replace(new RegExp(before_word, "g"), after_word);
} catch (e) {
    before_word = before_word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    text = text.replace(new RegExp(before_word, "g"), after_word);
};

console.log(text);
//結果:!!しんぶんし!!。下から読んでも、!!しんぶんし!!。

これで正規表現を使った置換もエラーを心配せずに実行できます。(たぶん)

ちなみに…

上記のコードの$1は、置換前の( )の中身がそのまま置換後へ反映される書き方です。

また、もし置換前に( )で囲まれた文字列が2つあれば、左から$1$2と書けばそれぞれ反映されます。

replace('(しん)ぶん(し)', '!!$1!!$2')
//結果:!!しん!!し

配列を使って一気に置換したいなぁ…

最後に配列を作って、一気に置換をする方法を紹介します。

まず、「置換したい文字列」と「置換後の文字列」を入れる2次元配列を作ります。

let replacement_words = [
    ['(しん.ん.)', '!!$1!!'],
    ['しんぶんし', 'イカとカイ'],
    ['下から読んでも', 'とてもおいしい'],
];

あとは、配列の長さを.lengthで取得してfor文を回せばOKです。

for (let i = 0; i < replacement_words.length; i++) {
    text = text
        .replace(new RegExp(replacement_words[i][0], "g"), replacement_words[i][1]);
};

これで、配列の長さが変わっても(文字列を追加や削除をしても)大丈夫です。

まとめ

ここまでの内容をまとめたコードです。

//元のテキスト
let text = 'しんぶんし。下から読んでも、しんぶんし。';

//置換したいテキストの2次元配列
let replacement_words = [
    ['(しん.ん.)', '!!$1!!'],
    ['しんぶんし', 'イカとカイ'],
    ['下から読んでも', 'とてもおいしい'],
];

try {
    for (let i = 0; i < replacement_words.length; i++) {
        text = text
            .replace(new RegExp(replacement_words[i][0], "g"), replacement_words[i][1]);
    };
} catch (e) {
    //エラー時の処理
    for (let i = 0; i < replacement_words.length; i++) {
        replacement_words[i][0] = replacement_words[i][0]
            .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
        text = text
            .replace(new RegExp(replacement_words[i][0], "g"), replacement_words[i][1]);
    };
};

console.log(text);
//結果:!!イカとカイ!!。とてもおいしい、!!イカとカイ!!。

さいごに

というわけで、JavaScriptreplace()メソッドの使い方と応用の忘備録でした。

では!(๑˃̵ᴗ˂̵)و

参考サイト・URL

正規表現 - JavaScript | MDN
正規表現とは、文字列内で文字の組み合わせを照合するために用いられるパターンです。 JavaScript では、正規表現はオブジェクトでもあります。これらのパターンは RegExp の exec() および test() メソッドや、String の match()、 matchAll()、replace()、repla...
Javascript での 正規表現 の エスケープ について - Qiita
Javascript : 正規表現 の エスケープ について . * + ^ | ( ) ? $ { }などの文字を文字列として正規表現の判定内で使いたい場合エスケープしなければならない。 正規表現リテラルで表す場...
タイトルとURLをコピーしました