正規表現 発展

和田です。最近はボリビアでゴーストしています。打倒サンタ・ブランカ・カルテル。

さて、前回は「正規表現 基礎」ということで基本的な正規表現を紹介しましたが、今回は発展形として、少し込み入った話になると思います。

前提条件

前回と同じく JavaScript 想定です。

動作確認は Node v6.10.0 で行っています。

目次

  • 後方参照 - (), (?:), \n, $n
  • 肯定先読み - x(?=y)
  • 否定先読み - x(?!y)

 

後方参照

正規表現では、グループ (()) 部分にマッチした文字列を記憶しておけます。

何に使うかといえば文字列の置換が主になるかと思います。以下、例です。

console.log(/(Moon).*\1/.test('Keith Moon looks the big Moon')); // true  
console.log(/(Moon).*\1/.test('Keith Moon looks the big moon')); // false

const str = '私の名前はNaoki Wadaです';  
const rep = str.replace(/([\w]+) ([\w]+)/, '$2 $1');  
console.log(rep); // 私の名前はWada Naokiです  

最初の2行のように、検索に使うこともできます。その場合 \n という表記を使用します。 n には () を使うごとに 1 からの数値が増加しつつ入ります。

4〜6行目は、置換の場合です。置換の場合は $n を使用します。こちらも () を使うごとに 1 ずつ増えていきます。

なお、グループを使用すると必ずマッチした文字列を記憶してしまうため、パフォーマンスが低下してしまします。

「後方参照は使わないけど、グループは使いたい」という場合、 (?:) が使用できます。

console.log(/(?:Moon).*\1/.test('Keith Moon looks the big Moon')); // false  
console.log(/(?:Moon)/.test('Keith Moon looks the big Moon')); // true

const str = '私の名前はNaoki Wadaです';  
const rep = str.replace(/(?:[\w]+) (?:[\w]+)/, '$2 $1');  
console.log(rep); // 私の名前は$2 $1です  
const rep2 = str.replace(/(?:[\w]+) (?:[\w]+)/, 'Wada Naoki');  
console.log(rep2); // 私の名前はWada Naokiです  

 

肯定先読み

jump-jumped-jumped  
cut-cut-cut  
study-studied-studied  
drive-drove-driven  

突然の、「現在形-過去形-過去分詞形」の羅列ですが、 cut-cut-cut のように変わらない動詞の現在形のみ取り出したい場合、以下のようになります。

const strs = ['jump-jumped-jumped', 'cut-cut-cut', 'study-studied-studied', 'drive-drove-driven'];  
strs.forEach((str) => {  
  const match = str.match(/^([\w]+)(?=-\1-\1)/);
  if(match !== null) {
    console.log(match[1]); // cut
  }
});

これは、「 -\1 が2つ続いた 直前の文字 」を取得するようになっています。この場合、 \1 の内容が jump, cut, study, drive になっていますので、一致するものは cut しかないという事になります。

 

否定先読み

北海道
青森県
東京都
神奈川県
京都府
大阪府
広島県

この中から「東京都」を見つける場合、以下のようになります。

const strs = '北海道,青森県,東京都,神奈川県,京都府,大阪府,広島県'.split(',');  
strs.forEach((str) => {  
  const match = str.match(/.*京都(?!府)/);
  if(match !== null) {
    console.log(match[0]);
  }
});

正規表現部分は、「京都という文字列の後に 『府』が付かないもの 」を取得するようになっています。そのため、否定先読みを除いた正規表現では「東京都」と「京都府」が一致しますが、否定先読みにより「京都府」が不一致になり「東京都」のみが一致するというふうになっています。


前回の基礎編と発展編の2編に渡ってお送りしました正規表現ですが、いかがだったでしょうか。

詳解 正規表現」を読んだほうが丁寧に書いてあるでしょうか、 少しでも参考になれば幸いです。