Help us understand the problem. What is going on with this article?

u (PCRE_UTF8) オプションをつけないと \h、\s、\v で想定しない文字を破壊するおそれがある

More than 5 years have passed since last update.

PCRE 関数のエスケープシーケンスのうち、\h (水平方向の空白文字)、\s (空白文字)、\v (垂直方向の空白文字) を使う場合、UTF-8 のオプション (u)をつけないと、preg_replace などで不要な文字を削除する際に想定しない文字を破壊するおそれがあります。

次のコードはひらがなの「だ」(U+3060) が破壊される様子を示したものです。「だ」の3番目のバイト (0xA0) がノーブレークスペース (U+00A0) と誤検出されてしまいます。

<?php

$str = "だ";

var_dump(
  "\xE3\x81\xA0" === $str,
  "\xE3\x81" === preg_replace("/\h/", "", $str),
  "e381" === bin2hex(preg_replace("/\h/", "", $str)),
  $str === preg_replace("/\h/u", "", $str)
);

Unicode で定義されるすべての文字 (U+0000 から U+10FFFF) に対してこれらのエスケープシーケンスを試すと、膨大な数の文字がマッチすることがわかります。u オプションをつけた場合でも、複数の文字がマッチしますので、それらの1つ1つが本当に想定した種類の文字であるのかどうかを検討する必要があります。u オプションをつけると、次の文字がマッチします。

U+0009 U+0020 U+00A0 U+1680 U+180E U+2000
U+2001 U+2002 U+2003 U+2004 U+2005 U+2006
U+2007 U+2008 U+2009 U+200A U+202F U+205F
U+3000 
<?php

print_matched_chars(function($char) {
    return preg_match('/\h/', $char);
});

function print_matched_chars(callable $callable) {

    for ($i = 0; $i < 0x110000; ++$i) {

        if ($i > 0xD7FF && $i < 0xE000) {
            continue;
        }

        $char = utf8_chr($i);
        $hex = strtoupper(dechex($i));

        if ($callable($char)) {
            echo 'U+',
            $i < 0x1000 ? str_repeat('0', 4 - strlen($hex)) : '',
            $hex, ': ' , $char, PHP_EOL;
        }

    }
}

function utf8_chr($cp) {

    if (!is_int($cp)) {
        exit("$cp is not integer\n");
    }

    if ($cp < 0 || (0xD7FF < $cp && $cp < 0xE000) || 0x10FFFF < $cp) {
        exit("$cp is out of range\n");
    }

    return mb_decode_numericentity('&#'.$cp.';', [0, 0x10FFFF, 0, 0x10FFFF], 'UTF-8');
}
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away