PHP/PCRE

Last-modified: 2012-11-10 (土) 12:48:35

正規表現の行末記号($)と\n、\rの関係

PHP PCRE 正規表現 http://jp2.php.net/manual/ja/pcre.pattern.php

$ は以下の位置にマッチする

  • D/m修飾子なしの場合
    • 文字列の最後
    • 文字列の最後が\nの場合はその直前
  • D修飾子付きの場合
    • 文字列の最後
  • m修飾子付きの場合
    • 文字列の最後
    • \nの直前 (文字列の最後に限らない)

注意

  • \n は \sにマッチする。\rも同様。
  • $ がマッチするのは位置であって、文字\nではない。
  • $ がマッチする位置は、 文字\r とは無関係。
  • m 修飾子は、$がマッチする条件を増やすものであり、依然としてパターンマッチは文字列全体に対して実施される。行ごとに区切ってパターンマッチを行うわけではない。
  • m 修飾子なしでも、$がマッチする位置は最大で2箇所ある。

<?php

// \sは\rと\nにもマッチする
echo "1: ";
$subject = "abc\r\ndef";
$result = preg_match('/(\s+)/', $subject, $matches);
echo "$result, " . rawurlencode($matches[1]) . "\n";
// 1, %0D%0A


// $ は文字列の最後にマッチする。
echo "2: ";
$subject = "abc";
$result = preg_match('/(c)$/', $subject, $matches);
echo "$result, " . rawurlencode($matches[0]) . ", " . rawurlencode($matches[1]) . "\n";
// 1, c, c

// $ は文字列の最後が\nの場合、その前にもマッチする。
// このとき、「マッチした文字列」に \n は含まれない。
// $がマッチするのは位置であって、文字ではないと理解する。
echo "3: ";
$subject = "abc\n";
$result = preg_match('/(c)$/', $subject, $matches);
echo "$result, " . rawurlencode($matches[0]) . ", " . rawurlencode($matches[1]) . "\n";
// 1, c, c

// $ は、文字列の途中の\nの前にはマッチしない。
echo "4: ";
$subject = "abc\nxyz";
$result = preg_match('/(c)$/', $subject, $matches);
echo "$result\n";
// 0

// $ は、文字列の途中の\nの前にはマッチしない。
// 文字列の最後に\nが連続していても例外ではない。
echo "5: ";
$subject = "abc\n\n";
$result = preg_match('/(c)$/', $subject, $matches);
echo "$result\n";
// 0

// D修飾子を付けると
// $ は、文字列の最後の\nの直前にはマッチしなくなる。
echo "6: ";
$subject = "abc\n";
$result = preg_match('/(c)$/D', $subject, $matches);
echo "$result\n";
// 0

// 注意。
// スペースで終わる文字列にマッチさせようとして \s$ という正規表現を使うと、
// スペースなしで\nで終わる文字列にもマッチする。
echo "7: ";
$subject = "abc\n";
$result = preg_match('/(c\s)$/', $subject, $matches);
echo "$result, " . rawurlencode($matches[1]) . "\n";
// 1, c%0A

// 注意。
// "abc\n"という文字列は、c$ にも c\s$ にもマッチする。(c\s$は No.8の例のとおり)
// $がマッチする位置は2箇所ある。
echo "8: ";
$subject = "abc\n";
$result = preg_match('/(c)$/', $subject, $matches);
echo "$result, " . rawurlencode($matches[1]) . "\n";
// 1, c

// $ がマッチする位置は、 文字\r とは無関係。
// $は、文字列最後の\rの直前にはマッチしない。
echo "9: ";
$subject = "abc\r";
$result = preg_match('/(c)$/', $subject, $matches);
echo "$result\n";
// 0

// $ がマッチする位置は、 文字\r とは無関係。
// $は、文字列最後の\r\nの直前にはマッチしない。
echo "10: ";
$subject = "abc\r\n";
$result = preg_match('/(c)$/', $subject, $matches);
echo "$result\n";
// 0

// m修飾子を付けると、
// $ は、文字列の途中の\nの前にもマッチする。
echo "11: ";
$subject = "abc\nxyz";
$result = preg_match('/(c)$/m', $subject, $matches);
echo "$result, " . rawurlencode($matches[1]) . "\n";
// 1, c

// 注意
// m修飾子を付けても、パターンは、\n をまたいでマッチする。
// 「行ごとに」パターンマッチするわけではない。
echo "12: ";
$subject = "abc\n \n \nxyz";
$result = preg_match('/(c\s+)$/m', $subject, $matches);
echo "$result, " . rawurlencode($matches[1]) . "\n";
// 1, c%0A%20%0A%20