Yuriko.Net 個別記事

2008-03-11
晴れ

mb_ereg_replace と 0x5c 文字に悩む

ゆりこ による 23:13:52 の投稿
カテゴリー: ソフトウェア
タグ:

WordPress 携帯対応プラグインKtai Style を携帯絵文字の入力対応にするべく作業中ですが、その検出のために mb_ereg_replace() を使ったところ、2バイト目が 0x5c な文字に悩まされました。

Ktai Style は携帯絵文字を <img localsrc="XXXX" /> というフォーマットで記録するのですが、EZweb の場合は以下のようなコードで正規表現で絵文字の Shift_JIS コードから変換させています。しかし、0xf35c など「2バイト目が 0x5c な文字」でエラーが出てしまいました。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バイト目の 0x5c が、次のダブルクォートをクォートしてしまい、閉じブラケット (]) が検出されなくなってしまうようです……。

PHP Parse error: syntax error, unexpected T_
STRING, expecting ‘]’ in /(ほげほげ)/ezweb.php(1905) : mbregex replac
e on line 2

対策をいろいろ考えてみましたが、正規表現オプションの “e” 用のコードで \1 でマッチした部分を取り出すことが原因なので、「e オプションを使わない」もしくは「\1 でマッチした部分を取り出すのをやめる」のどちらが対策となります。それは避けたいため、2バイト目が 0x5c な文字はマッチ条件から除外して、あとで処理することにしました。

$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 を入れても問題ありません。しかし、絵文字コードにシングルクォート(‘)、ダブルクォート (“) を含むことがあって、そういう文字と 0x5c を含む文字が結合すると、これまたうまく処理できません。仕方ないので、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 は近日中にリリースできることでしょう!!

トラックバック・コメント »

コメントはありません。

上に戻る

※スパム対策プラグインの影響により、すぐにトラックバックが反映されない場合があります。お手数ですが、半日ほど待ってみてください。

コメント投稿

※発言の責任を明確にするため「名無し」「通りすがり」「匿名希望」等の匿名は不可とします。捨てハンドルでもいいので必ず名乗ってください。
XHTML (使えるタグ): <a href="" title="" ktai=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <img localsrc="" alt=""> .
※スパム対策プラグインの影響により、すぐにコメント内容が表示されない場合があります。お手数ですが、半日ほど待ってみてください。

上に戻る