2008年3月11日の投稿

mb_ereg_replace と 0×5c 文字に悩む
WordPress 携帯対応プラグインKtai Style を携帯絵文字の入力対応にするべく作業中ですが、その検出のために mb_ereg_replace() を使ったところ、2バイト目が 0×5c な文字に悩まされました。
Ktai Style は携帯絵文字を <img localsrc="XXXX" /> というフォーマットで記録するのですが、EZweb の場合は以下のようなコードで正規表現で絵文字の Shift_JIS コードから変換させています。しかし、0xf35c など「2バイト目が 0×5c な文字」でエラーが出てしまいました。self::$pics は、絵文字コードをキー、絵文字自体を値とする配列です。ソースコードは Shift_JIS で書かれているため、バックスラッシュじゃなくて円マークで正当です。
$pics = array_flip(self::$pics);
if (! $pics) {
return $buffer;
}
mb_regex_encoding($this->charset);
$replaced = mb_ereg_replace(
"([¥xf3¥x40-¥xf3¥xfc]|[¥xf4¥x40-¥xf4¥xfc]|[¥xf6¥x40-¥xf6¥xfc]|[¥xf7¥x40-¥xf7¥xfc])",
'isset($pics["¥1"]) ?
"<"img localsrc=¥"" . $pics["¥1"] . "¥" />"" :
sprintf("&t;img localsrc=¥"ez¥" alt=¥"[0x%x%x]¥" />", ord(substr("¥1",0,1)), ord(substr("¥1",1,1)))',
$buffer, 'e');
出たエラーは以下のようなものです。マッチした文字を \1 によって代入した時点で、2バイト目の 0×5c が、次のダブルクォートをクォートしてしまい、閉じブラケット (]) が検出されなくなってしまうようです……。
PHP Parse error: syntax error, unexpected T_
STRING, expecting ‘]’ in /(ほげほげ)/ezweb.php(1905) : mbregex replac
e on line 2
対策をいろいろ考えてみましたが、正規表現オプションの “e” 用のコードで \1 でマッチした部分を取り出すことが原因なので、「e オプションを使わない」もしくは「\1 でマッチした部分を取り出すのをやめる」のどちらが対策となります。それは避けたいため、2バイト目が 0×5c な文字はマッチ条件から除外して、あとで処理することにしました。
$replaced = mb_ereg_replace(
"([¥xf3¥x40-¥xf3¥x5b]|[¥xf3¥x5d-¥xf3¥xfc]|[¥xf4¥x40-¥xf4¥x5b]|[¥xf4¥x5d-¥xf4¥xfc]|[¥xf6¥x40-¥xf6¥x5b]|[¥xf6¥x5d-¥xf6¥xfc]|[¥xf7¥x40-¥xf7¥x5b]|[¥xf7¥x5d-¥xf7¥xfc])",
'isset($pics["¥1"]) ?
"<img localsrc=¥"" . $pics["¥1"] . "¥" />" :
sprintf("<img localsrc=¥"ez¥" alt=¥"[0x%x%x]¥" />", ord(substr("¥1",0,1)), ord(substr("¥1",1,1)))',
$buffer, 'e');
if ($replaced) {
$replaced = mb_ereg_replace("¥xf3¥x5c", '<img localsrc="' . $pics["¥xf3¥x5c"] . '" />', $replaced);
$replaced = mb_ereg_replace("¥xf4¥x5c", '<img localsrc="' . $pics["¥xf4¥x5c"] . '" />', $replaced);
$replaced = mb_ereg_replace("¥xf6¥x5c", '<img localsrc="' . $pics["¥xf6¥x5c"] . '" />', $replaced);
$replaced = mb_ereg_replace("¥xf7¥x5c", '<img localsrc="' . $pics["¥xf7¥x5c"] . '" />', $replaced);
}
なんとも見苦しいコードですが、まあ仕方ないでしょう……。ソフトバンク絵文字は「ウェブコード」という、ESC-$-X-Y-SI という文字群で、マルチバイト対応の正規表現を使う必要がないため、preg_replace() が使えます。preg_replace ならば ‘e’ オプション用のコードで $1 を入れても問題ありません。しかし、絵文字コードにシングルクォート(‘)、ダブルクォート (“) を含むことがあって、そういう文字と 0×5c を含む文字が結合すると、これまたうまく処理できません。仕方ないので、preg_match() でマッチした文字を変数に取り出し、分解してから substr_replace() で戻すという、さらに泥臭い手法になりました……。
// ==================================================
public function pictogram_index($webcode) {
if (preg_match('/¥x1b.(.)(.)¥x0f/', $webcode, $c)) {
$c2 = ord(stripslashes($c[2]));
return $c[1] . ($c2 ? $c2 : '92');
} else {
return '0';
}
}
/* ==================================================
* @param string $buffer
* @return string $buffer
*/
public function pickup_pics($buffer) {
$pics = array_flip(array_map(array($this, 'pictogram_index'), self::$pics));
if (! $pics) {
return $buffer;
}
for ($offset = 0 , $replace = 'X' ;
preg_match('/¥x1b.([GEFOPQ])([!-z]+)¥x0f/', $buffer, $webcode, PREG_OFFSET_CAPTURE, $offset) ;
$offset += strlen($replace))
{
$orig = $webcode[0][0];
$offset = $webcode[0][1];
$seq = $webcode[1][0];
$char = $webcode[2][0];
$replace = '';
for ($i = 0 ; $i < strlen($char) ; $i++) {
if (isset($pics[$seq . ord($char[$i])])) {
$replace .= '<img localsrc="' . $pics[$seq . ord($char[$i])] . '" />';
} else {
$replace .= '<img localsrc="s" alt="[ESC$' . $seq . ord($char[$i]) . 'SI]" />';
}
}
$buffer = substr_replace($buffer, $replace, $offset, strlen($orig));
}
return $buffer;
}
ともあれ、絵文字入力は問題なく動作するようになりました。WordPress 2.5 はリリース延期になったようですが、ベータ版での動作は確認できているので、Ktai Style 1.20 は近日中にリリースできることでしょう!!

上に戻る