by shigemk2

当面は技術的なことしか書かない

WebDBPress Vol.58 PHP転ばぬ先の杖 その3

文字エンコーディングと正規表現

PHPの文字エンコーディング

  • ISO-2022-JP

日本語Eメールでよく使われる。

古いガラケーでも使える文字コード。プログラムやDBでの設定は非推奨なので注意すべし。

昔プログラムやDBで使われていた文字コードだが、今はutf-8にその座を奪われている。

日本語だけでなくアジア圏、ヨーロッパ圏でも使われる文字エンコードで今はこれが主流だったりする。

ので、新規案件はutf-8に指定するのが望ましい。

文字エンコードPHPのどこで使われるかというと、

  1. PHP が出力する HTML
  2. PHP プログラム自体
  3. PHP が接続する DB エンジン

の3つ。HTMLはともかく、プログラムやDBの文字エンコードは統一しないとトラブルのもとになる。

日本語の文字列を扱うPHP関数として、iconvとmbstringがあるが、
iconvはPHP同梱ではなく環境に依存してしまうため、現在でもメンテナンスが続けられていて
PHPに同梱されているmbstringを使うことが推奨される。

正規表現

最長一致に気をつけるべし
正規表現を使って、

<a name="bar">bar</a>

という結果を出したいとき、どうしたらよいのか?

<?php
$html='<a href="#foo">foo</a><a name="bar">bar</a>'; preg_match('/<a.*>bar<\/a>/', $html, $matches); var_dump($matches[0]);
?>

結果は次のようになる。

string(43) "<a href="#foo">foo</a><a name="bar">bar</a>"

最長一致といっても、どこのアンカータグなのかを指定しきれていないので、
上記のような結果になってしまったと考えらる。

ちなみに、最短一致を利用しても、

<?php
$html='<a href="#foo">foo</a><a name="bar">bar</a>'; preg_match('/<a.*?>bar<\/a>/', $html, $matches); var_dump($matches[0]);
?>

同じ結果となる。

string(43) "<a href="#foo">foo</a><a name="bar">bar</a>"

最短一致を利用しても、どこのアンカータグなのか分からないから。

欲しい検索結果を出したいときは、このように書くと良いようだ。

<?php
$html='<a href="#foo">foo</a><a name="bar">bar</a>'; preg_match('/<a[^>]*>bar<\/a>/', $html, $matches); var_dump($matches[0]);
?>

結果はこのようになった。

string(21) "<a name="bar">bar</a>"

'>' まで読み進めるのに '>' 以 外の文字の 0 回以上繰り返しと書くことが肝要なようだ。
上記2つだと、ずっと先までアンカータグを検索してしまうらしい。

正規表現関数の選択
バイナリセーフではないため、ereg関数は推奨できない。

PCRE関数はPHP同梱ではないため、環境に依存する。
また、日本語文字列を正規表現させたい場合は、
u修飾子を使う(ただし、utf-8サポートなしでライブラリがコンパイルされていた場合、u修飾子も使えないことは注意すべし)

mb_ereg関数(マルチバイト正規表現関数)
mbstringエクステンションの一部(PHPに同梱されている)
多くの文字エンコーディングに対応している「鬼車」を使っている。

ただ、mb_ regex_encoding関数で正規表現および検索対象文字列の文字エンコーディングを指定する
必要がある。指定しないと環境によっては別のエンコーディングで正規表現を始めてしまう事もある。

また、正規表現パターンはシングルクォートで囲むのが望ましい。
(ダブルクォートよりは混乱が減る)