駐:すでにオチが付いております。
悲しいかなPHPには、他の言語で使えるMODULE.JP - 日本語に絡むUnicodeブロックとスクリプト(正規表現)にあるような
\p{InHiragana}
という表現がない*1ので、正規表現で入力されてきたUTF-8文字列がひらがなかどうかを判定するためには、
<?php function isHiragana($str){ return preg_match('/^(\xe3\x81[\x81-\xbf]|\xe3\x82[\x80-\x9e])+$/',$str); }
みたいなコードを書かなくてはいけない*2。
で、色々なところで文字コード表を参考に書けばいいよみたいなことが書いてあったから、参考にしてisSymbolを書こうと思ったんだけど、「U+2000-U+206F」とか書いてあるわけ。
Unicodeの16進表現をUTF-8のバイト列を得る方法が分からなくて、調べていたんだけれども、どうも探し方が悪いのか、見つからないので自分で書いてみた。
そしたら、ものすごく長くなったので、もっと頭のいい方法があれば*3教えてください。
っつか、こういうコードが書けないのバレバレ。
追記:
この記事を書き終わって5分後、なんとなく思いついて、恐々と書いてみた。
<?php //U+3042(あ) var_dump(mb_convert_encoding(pack("H*", "3042"), "UTF-8", "UCS-2"));
でいいんじゃん…orz
「もっと頭のいい方法があれば」とか!
文字コードの勉強になったと思うこととする…
追記2:
php -r 'var_dump(bin2hex(mb_convert_encoding(pack("H*", "ff10"), "UTF-8", "UCS-2")));'
以下追記前に書いたコード
<?php ini_set("mbstring.language", "Japanese"); ini_set("mbstring.script_encoding", "UTF-8"); ini_set("mbstring.internal_encoding", "UTF-8"); if(isset($_SERVER["argv"][1]) == false){ echo "pass unicode like U+2000 or just specify charactor\n"; exit; } $unicode = $_SERVER["argv"][1]; $bytes = array(); if(strpos($unicode, "U+") === false || strlen($unicode) % 2 != 0){ if(mb_strlen($unicode) == 1){ $t = unistr_to_ords($unicode, "UTF-8"); $t = $t[0]; if($t <= 0xFF){ $unicode = "00" . dechex($t); }else if($t <= 0xFFFF){ $unicode = dechex($t >> 8) . dechex($t & 0xFF); } $unicode = "U+" . $unicode; }else{ echo "pass unicode like U+2000 or just specify charactor\n"; exit; } } for($i = 1; $i < strlen($unicode) / 2; $i++){ $bytes[] = hexdec(substr($unicode, $i * 2, 2)); } $fb = $bytes[0]; $sb = $bytes[1]; $utf = array(); if(count($bytes) == 2){ $t = ($fb << 8) + $sb; if($fb == 0 && $sb <= 127){ // U+0000 - U+007F $utf[0] = $fb; $utf[1] = $sb; }else if($fb >= 0 && $fb <= 7){ // U+0080 - U+07FF $utf[0] = (($t & 1984) >> 6) + 192; $utf[1] = ($t & 63) + 128; }else if($fb >= 8 && $fb <= 255){ // U+0800 - U+FFFF $utf[0] = (($t & 61440) >> 12) + 224; $utf[1] = (($t & 4032) >> 6) + 128; $utf[2] = ($t & 63) + 128; } }else if(count($bytes) == 3){ //U+10000 - U+1FFFFF $tb = $bytes[2]; $t = ($tb << 16) + ($fb << 8) + $sb; $utf[0] = (($t & 3670016) >> 19) + 240; $utf[1] = (($t & 516096) >> 13) + 128; $utf[2] = (($t & 8064) >> 7) + 128; $utf[3] = ($t & 127) + 128; }else{ echo "pass unicode like U+2000 or just specify charactor\n"; exit; } $utf8_bytes = array(); $utf8_str = ""; foreach($utf as $u){ $hex = dechex($u); $hex = (strlen($hex) == 1) ? "0" . $hex : $hex; $utf8_bytes[] = '0x' . strtoupper($hex); $utf8_str .= $hex; } echo "UTF-8 for Unicode " . $unicode . "(" . pack('H*', $utf8_str) . ") is "; echo implode(",", $utf8_bytes) . "(" . count($utf8_bytes) . "bytes)\n"; /* By Darien Hager, Jan 2007... Use however you wish, but please please give credit in source comments. Change "UTF-8" to whichever encoding you are expecting to use. */ function unistr_to_ords($str, $encoding = 'UTF-8'){ // Turns a string of unicode characters into an array of ordinal values, // Even if some of those characters are multibyte. $str = mb_convert_encoding($str,"UCS-4BE",$encoding); $ords = array(); // Visit each unicode character for($i = 0; $i < mb_strlen($str,"UCS-4BE"); $i++){ // Now we have 4 bytes. Find their total // numeric value. $s2 = mb_substr($str,$i,1,"UCS-4BE"); $val = unpack("N",$s2); $ords[] = $val[1]; } return($ords); }
で、
[kent@localhost hatena]$ php -f misc/ucsTest.php "U+0061" UTF-8 for Unicode U+0061(a) is 0x00,0x61(2bytes) [kent@localhost hatena]$ php -f misc/ucsTest.php "U+0060" UTF-8 for Unicode U+0060(`) is 0x00,0x60(2bytes) [kent@localhost hatena]$ php -f misc/ucsTest.php "U+0065" UTF-8 for Unicode U+0065(e) is 0x00,0x65(2bytes) [kent@localhost hatena]$ php -f misc/ucsTest.php "カ" UTF-8 for Unicode U+ff76(カ) is 0xEF,0xBD,0xB6(3bytes) [kent@localhost hatena]$ php -f misc/ucsTest.php "あ" UTF-8 for Unicode U+3042(あ) is 0xE3,0x81,0x82(3bytes) [kent@localhost hatena]$ php -f misc/ucsTest.php "い" UTF-8 for Unicode U+3044(い) is 0xE3,0x81,0x84(3bytes)
って使います。
参考