[PHP] 指定した文字列/パターンを含むかチェックする際の注意点
はじめに
WEBチームの日下部です。
よくstrpos()やpreg_match()の返り値がどうなってたか忘れて調べるので忘備録ついでに地味な注意点とともにまとめました。
指定した文字列/パターンを含むかどうかにだけ焦点を当てており、一部機能だけの説明となるため、各関数の詳細はマニュアルを参照してください。
全体的に言えること
値の比較には、理由がない限り ==, != ではなく ===, !== を使いましょう。
特に 0 == FALSE が TRUE になることを意外に感じる場合は、型の比較表を見ることを推奨します。
目次
- 指定した文字列を含むかチェックする
- 指定したパターンを含むかチェックする
- 配列からパターンにマッチする要素を抽出する
指定した文字列を含むかチェックする
strpos() [Manual]
int strpos(string $heystack, mixed $needle)
引数
heystack: 検索対象の文字列。
needle: 探す文字列。文字列型以外の指定も可能ですが...(後述)
返り値
heystackの中で最初にneedleが出現する位置(先頭が0)を返します。
heystackの中にneedleが含まれない場合はFALSEを返すので、
strpos($heystack, $needle) !== FALSE
の値をみることで存在チェックが可能。
注意点1
heystackの先頭にneedleが出現する場合の返り値は0のため
strpos($heystack, $needle) != FALSE
は「文字列が先頭に出現する」ときにFALSEとなってしまいます。必ず型も比較するようにしましょう。
注意点2
マニュアルに
needleが文字列でない場合は、それを整数に変換し、その番号に対応する文字として扱います。
とありますが、これは
「needleが文字列でなければ整数にキャストしてから文字列にキャストする」
ということではありません。(整数にキャストまでは合っています)
needleが文字列でないときは、整数にキャストしたneedleを10進ASCIIコードとみなした場合に対応する文字として扱います。
つまり次の2つは等価ではなく、
strpos('2100', 100) strpos('2100', (string)(int)100) // needleは文字列の100になる
次の3つは等価です。
strpos('2100', 100) strpos('2100', chr((int)100)) strpos('2100', 'd')
意図しない結果を避けるため、特別な事情がない限りneedleには文字列を指定したほうがよいでしょう。
chr()についてはこちら
PHP: chr - Manual
注意点3
needleに配列をつっこんでもエラーとなりませんが、これはneedleを複数指定できるわけではなく、ただ配列が整数にキャストされるだけです。
#PHP 7.0時点では配列を整数にキャストすると、空の配列の場合は0に、空でない場合は1になります。
strstr() [Manual]
needleが最初に現れる位置を見つけ、そこから文字列の終わりまでを返す関数です。
needleが見つからない場合はFALSEを返すので、存在チェックに利用できますが、そのためだけにこの関数を使うことは推奨されません。
注意:
もし特定の haystack に needle があるかどうかを調べるだけの場合、より高速でメモリ消費も少ない strpos() を代わりに使用してください。
指定したパターンを含むかチェックする
preg_match() [Manual]
int preg_match(string $pattern, string $subject)
返り値
subject内にpatternにマッチする文字列があれば1を、なければ0を、マッチング処理にエラーが発生した場合はFALSEを返します。存在チェックをする場合は
preg_match($pattern, $subject) === 1
がTRUEかどうかをみれば良いです。
注意点
マッチしなかったのかエラーが発生したのかを区別する必要がある場合は、0 == FALSE がTRUEになることに気を付けましょう。
配列からパターンにマッチする要素を抽出する
ここでは配列
$input = ['first', 'second', 'third', 'fourth', 'fifth'];
から末尾がthで終わる要素を取り出す例を考えます。
これにはpreg_grep()を使うのが簡単です。
preg_grep() [Manual]
array preg_grep(string $pattern, array $input)
返り値
inputの要素のうち、patternにマッチする要素を抽出した配列
例:
preg_grep('/th$/', $input) // ['fourth', 'fifth']
これは
array_filter($input, function($s) { return preg_match('/th$/', $s) === 1; })
と等価です。
注意点
preg_grep()の第三引数に定数PREG_GREP_INVERTを指定すると、パターンにマッチしない要素を取り出します。マッチング処理がエラーとなる場合も取り出します。つまり次の二つは等価です。
preg_grep('/th$/', $input, PREG_GREP_INVERT) array_filter($input, function($s) { return preg_match('/th$/', $s) !== 1; })
#「パターンにマッチ"する"要素を取り出す」ことを明示的に指定するための定数は定義されていないため、マッチする要素を取り出す場合は第三引数を省略するか、0を指定します。