正規表現:改行を含めて、複数行でマッチングする方法

最終更新:2019-10-12 by Joe

正規表現において、通常、特殊文字「.」は「改行を除くすべての文字」を表現します。頻繁に利用する「.」ですが、改行を越えてすべての文字を吟味できません。改行を含めて文字列マッチを見つける方法をまとめました。

改行を含めて複数行を検索する方法

特殊文字の「.(ドット)」は「改行以外の1文字」を意味します。

これと量指定子の「*(0回以上の連続)」などを利用して、任意の文字列をマッチさせる正規表現「.*」はよく利用しますが、注意が必要なのは、文字列中に「改行」があるとそこで途切れてしまうという点です。

今回、改行を含めて、文字列の検索を行う方法をまとめてみます。

方法1エスケープシーケンス「\s\S」を利用する

「改行を含めたすべての文字列」を対象としたい時は、下記の2つのエスケープシーケンス表現を利用します。

  • \s :空白、タブ、フォーム フィードなどの任意の空白文字
  • \S:空白文字以外の任意の文字

これらは、互いに反対の関係です。PHPでの使用例を見てみます。

改行を含めて複数行をマッチさせる(PHP)

$subject = '
The text you
need to search.
';

// 改行コードを含むべての文字列
if ( preg_match( '/[\s\S]*/', $subject ) )
  echo "Matched";

[]の角括弧による表現は、「文字セット」や「文字クラス」と呼ばれ、カッコ内にふくまれるすべての文字を対象とします。

上記の例は、\sか、\Sのいずれかの文字、すなわち「空白を含むすべての文字」で、0回以上繰り返す、最長のマッチを探す事になります。

方法2パターン修飾子を適応し、「.」の振る舞いを変える

正規表現における改行コードの取り扱いに関して、シングルラインモード、マルチラインモードという2つのモードを切り替えられるのが一般的です。例えば、 PHP (PCRE)や Perl では、修飾子「m」と「s」で「$」が表す行末の定義や、「.(ドット)」が改行コードを含むかどうかを変更できます。

PCREのデフォルトモード

  • ^: 文字列全体のの最初
  • $: 文字列全体の末尾
  • . : 改行コードを除くすべての文字

m モード(マルチラインモード)

  • ^: 各行の最初
  • $: 各行の末尾
  • . : 改行コードを除くすべての文字(デフォルトと同じ)

s モード(シングルラインモード)

  • ^: 文字列全体のの最初(デフォルトと同じ)
  • $: 文字列全体の末尾(デフォルトと同じ)
  • . : 改行コードを含むすべての文字

PHPドキュメントより、該当の記述を抜粋します:

修飾子意味
m (PCRE_MULTILINE)デフォルトで、PCRE は、検索対象文字列を(実際には複数行からなる 場合でも)単一の行からなるとして処理します。 「行頭」メタ文字 (^) は、対象文字列の最初にしかマッチしません。 一方、「行末」メタ文字 ($) は、文字列の最後、または (D 修飾子が設定されていない場合) 最後にある改行記号の前のみにしかマッチしません。 この動作は Perl と同じです。 この修飾子を設定すると、「行頭」および「行末」メタ文字は 対象文字列において、文字列の最初と最後に加えて、 各改行の直前と直後にそれぞれマッチします。 この動作は、Perl の /m 修飾子と同じです。 対象文字列の中に "\n" 文字がない場合や、 またはパターンに ^ または $ がない場合は、 この修飾子を設定しても意味はありません。
s (PCRE_DOTALL)この修飾子を設定すると、パターン中のドットメタ文字は 改行を含む全ての文字にマッチします。 これを設定しない場合は、改行にはマッチしません。 この修飾子は、Perl の /s 修飾子と同じです。 [^a] のような否定の文字クラスは、 この修飾子の設定によらず、常に改行文字にマッチします。

つまりPHPでは下記のような表現で、改行を含むすべての文字列が処理可能です。

$subject = '
The text you
need to search.
';

// 改行コードを含むべての文字列
if ( preg_match( '/.*/s', $subject ) )
  echo "Matched";

モードの切り替えによって「.」の意味だけでなく「^」の意味が混乱しやすいので、注意が必要です。不要な混乱をさけるため、筆者はあまり積極的にはシングルラインモードを使いません。

参考リンク

ドットメタ文字の振る舞いは、各正規表現エンジンで振る舞いが異なるため、各言語の仕様をよく確認しながら進める必要があります。