[JS]文字列操作: 連続する文字列を変換する方法
replaceを用いた文字列操作
replace
メソッドと正規表現を使って、連続する特定の文字列を一つにまとめる方法を解説します。
以下のコードは、連続するハイフンを一つのハイフンに置き換える例です。
let str = "hello---world--example";
let result = str.replace(/-+/g, "-");
console.log(result); // "hello-world-example"
g
オプションを付けることで、文字列全体に対して正規表現を適用し、該当するすべての部分を置き換えます。ここで、正規表現の便利なオプションである g
オプションと i
オプションについて詳しく見ていきます。
gオプション: すべての一致部分を置換する
g
オプションは、指定した文字列が複数回登場する場合、そのすべてを置き換えるためのオプションです。例えば、ウェブサイトのドメイン名が変更になり、古いURLをすべて新しいドメインに変更する必要がある場合を考えます。
var content = "私たちのウェブサイトはhttp://oldsite.comで見つけられます。詳細はhttp://oldsite.com/contactをご覧ください。";
content = content.replace(/http:\/\/oldsite\.com/g, "http://newsite.com");
console.log(content);
// "私たちのウェブサイトはhttp://newsite.comで見つけられます。詳細はhttp://newsite.com/contactをご覧ください。"
正規表現で g
オプションを使用することで文字列全体にわたって「http://oldsite.com」を検索し、すべての一致部分を「http://newsite.com」に置き換えています。g
オプションがないと、最初の一致部分しか置き換えられません。
iオプション: 大文字と小文字を区別しない検索
i
オプションは、大文字と小文字を区別せずに検索を行いたい場合に使います。例えば、ユーザーから入力されたメールアドレスが正しいかどうかをチェックする際に、大文字と小文字を区別せずに検索を行いたい場合があります。
var email = "User@Example.com";
var isValid = email.match(/user@example\.com/i);
console.log(isValid); // ["User@Example.com"]
i
オプションを使用することで、「user@example.com」という文字列を大文字・小文字を区別せずに検索しています。この場合、「User@Example.com」という入力に対しても正しくマッチします。
名前付きグループとgオプションの併用
次に、正規表現の「名前付きグループ」とg
オプションの併用について説明します。
名前付きグループとは
名前付きグループとは、正規表現のグループに名前を付け、その名前でマッチした文字列を取り出すことができる機能です。例えば、以下の例では、メールアドレスのドメイン部分を取り出しています。
const result = 'alice@example.com'.match(/@(?<domain>.+)/);
console.log(result.groups.domain); //=> example.com
この正規表現では、@
の後に続く任意の文字列 (.+
) を「domain」という名前付きグループに格納し、match
メソッドを使って、.groups
プロパティを利用し、domain
という名前付きグループにマッチした部分を取得しています。
名前付きグループとgオプションの問題
g
オプションと名前付きグループを組み合わせると、通常のmatch
メソッドでは、名前付きグループを使った結果を.groups
で参照できなくなるという問題があります。
const result = '123'.match(/(?<digit>\d)/g);
console.log(result); //=> ["1", "2", "3"]
この正規表現では、数字 (\d
) を「digit」という名前付きグループに格納し、g
オプションでそれぞれの数字を全て検索しており、 match
メソッドを使うと、名前付きグループが無視され、マッチした文字列のみが返されます。この問題を解決する一つの方法として、RegExp.prototype.exec
メソッドを使用することができます。
const regexp = /(?<digit>\d)/g;
let match;
const result = [];
while ((match = regexp.exec('123')) !== null) {
result.push(match.groups);
}
console.log(result);
// => [{ digit: '1' }, { digit: '2' }, { digit: '3' }]
exec
メソッドは、正規表現でマッチした各項目を繰り返し処理するために使います。ここでは、while
ループを使って、各マッチ結果の名前付きグループをresult
配列に追加しています。結果として、すべての数字が「digit」という名前付きグループに格納され、配列にまとめられます。
splitとjoinを使った文字列操作
文字列操作では、split
メソッドで文字列を分割し、join
メソッドで再度結合する方法も便利です。
let str = "This
is a test.";
let result = str.split(/\s+/).join(' ');
console.log(result); // "This is a test."
正規表現 \s+
を使って、複数の空白文字を一つの空白で分割し、join(' ')
で分割した部分を一つの空白文字で結合しています。
reduceを使った文字列操作
また、reduce
メソッドを使って、文字列を一つに変換することもできます。
let str = "This is a test.";
let result = str.split('').reduce((acc, char) => {
if (char === ' ' && acc.endsWith(' ')) {
return acc;
}
return acc + char;
}, '');
console.log(result); // "This is a test."
split('')
で文字列を一文字ずつ配列に変換し、reduce
を使って、連続する空白を一つにまとめる処理を行います。acc
は蓄積された結果、char
は現在の文字です。acc.endsWith(' ')
で蓄積された結果が空白で終わっているかどうかを確認します。もしそうであれば、次の空白は無視されます。
Discussion
typed-regexライブラリを使うとパターンマッチした部分の補完も出てくれるようでした
定義側
使用側