PHP正規表現での質問です。

preg_match_allを使って機種依存文字を探し出しすコードを書いているのですが、うまくいきません。
下のものではうまくいくのですが、例えば"ユユ"という文字を$dddに入れると、
ユのコードが8386なので83「8683」86で反応するようです。
http://q.hatena.ne.jp/1189143057←ここと同じです。
やはりmbを使ったり文字を全部並べたりしたり…無理やりでないと難しいでしょうか?
できれば\x○○の形で頑張りたいのですが…
何かアドバイスをもらえると助かります。
※SJISなのにSJISでエンコしてるのはEUCも試したときの名残なので無視してください…
コード↓
<meta http-equiv="Content-Type" content="text/html; charset=Shift_Jis" />
</head><body>
<?
$ddd = "①";
$ddd = htmlspecialchars(mb_convert_encoding($d3, "SJIS", "auto"));

$regdat = '('
.'[\x85-\x87][\x40-\xFC]|\x88[\x40-\x9D]|' //9~15区
.'[\xEB-\xFC][\x40-\xFE]' //85~94区
.')';

if(preg_match_all("/".$regdat."/e",$ddd,$title03)){
$di = mb_convert_encoding(join("",$title03[0]), "SJIS", "auto");
$did = $di . " という機種依存文字が含まれています。";
echo $did;
}
?>
</body>
=====

回答の条件
  • 1人2回まで
  • 登録:2008/08/13 19:12:35
  • 終了:2008/08/14 11:25:05

ベストアンサー

id:pahoo No.1

pahoo回答回数5960ベストアンサー獲得回数6332008/08/13 21:29:46

ポイント60pt

まず、preg系関数は、日本語のようなマルチバイト文字には対応していません。

ただ、パターン修飾子の 'u' を用いたときに限り、UTF-8 に対して正規表現を適用できるのですが、Unicode表は句点コードと違うので、16進コードで機種依存文字領域を指定するのは難しいです。


tukihatuさんもお察しのように、mb_ereg系関数を使うのが代替案になります。

$ddd = "123④567⑧9ユユ0";

$regdat = '('
.'[\x85-\x87][\x40-\xFC]|\x88[\x40-\x9D]|' //9~15区
.'[\xEB-\xFC][\x40-\xFE]' //85~94区
.')';

mb_ereg_search_init($ddd, $regdat);
while (1) {
    $arr = mb_ereg_search_pos();
    if ($arr == FALSE)  break;
    $di = substr($ddd, $arr[0], 2);
    echo $di . " という機種依存文字が含まれています。<br />";
    mb_ereg_search_setpos($arr[0] + 2);
}

ところが、このサンプルは PHP4.x では動きますが、PHP5.xでは動かない可能性があります。


PHP5.xからは、エンジンとして鬼車が採用されたため、この表現では正常に処理されません。

そうなると、16進コード表記による正規表現は諦めるか、16進コードにこだわるのであればsubstr関数で1バイトずつ取り出し、区点コードを調べていくしかないと思います。

id:tukihatu

あー、そうですねえ…/uでやるのも考えたんですが範囲がちょっと…

substrで、ぶつ切りも考えたのですが、数が多くなると処理落ちすると思うので無いですね…

やはり一個ずつつぶして行こうと思います。バグが無いほうが一番ですし。

「鬼車」の場合、コード表記は\x85等では無理なんですか?

補記 4読んだけどいまいちわからない…

1. 16進数字タイプ追加 (\h, \H)←これですか?

今試して見たけどたしかに5じゃ出来ないですね・・・

追記:解決しました。ありがとうございます。

とりあえず\x○○をつかって、php4と5で処理を分けることにします。

2008/08/14 11:24:44
  • id:tukihatu
    あ、/eが入ってるのも無視してください…消し忘れです。
  • id:pahoo
    たとえば "\x87\x43" は受け付けてくれるのですが、"\x87[\x40-\x4F]" のように上位/下位バイトを分離した範囲指定はできません。また、戻り値の位置も PHP4.x とは異なり、バイト位置ではなく、文字単位での位置を返してくれます。
    マルチバイト文字の場合、シフトJISやEUC-JPは“たまたま”2バイトですが、2バイトを超えるマルチバイト文字もある(PHP5.xでは最大6バイトまで対応している)ため、1バイト単位での分離を認めていないものと思われます。
  • id:tukihatu
    いろいろやってみましたが、13区や89区の範囲指定は、pregでもmbでもうまく拾ってくれませんね…
    一個途中で抜けたり…そこだけコードが違うんでしょうかね…
    全部一個ずつ書くからいいですけど。
  • id:tukihatu
    とりあえず一個ずつ潰したらいい感じになりました。
    続きはトラックバックのtukihatuブログで。

この質問への反応(ブックマークコメント)

トラックバック

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません