正規表現において、通常、特殊文字「.」は「改行を除くすべての文字」を表現します。頻繁に利用する「.」ですが、改行を越えてすべての文字を吟味できません。改行を含めて文字列マッチを見つける方法をまとめました。
改行を含めて複数行を検索する方法
特殊文字の「.(ドット)」は「改行以外の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";
モードの切り替えによって「.」の意味だけでなく「^」の意味が混乱しやすいので、注意が必要です。不要な混乱をさけるため、筆者はあまり積極的にはシングルラインモードを使いません。
参考リンク
ドットメタ文字の振る舞いは、各正規表現エンジンで振る舞いが異なるため、各言語の仕様をよく確認しながら進める必要があります。