近年はWebで文字化けを見ることがずいぶんと減ったかと思いますが、古いシステムを使っていたり、メールを送信したり、ガラケー向けのWebサイトを作ったりする場合に、機種依存文字(NEC機種依存文字、IBM拡張文字など)に困ることがあります。
ちなみに携帯Twitterでは機種依存文字がガラケーで表示されません。
Twitter / @loglesslove: 濵﨑髙德(はまさきたかのり)さんは携帯Twitterで表示される?
そんなわけで、全部の機種依存文字を判定するにはどうすればいいんだ?と思ってPHPで作ってみました。
機種依存文字判定ツール
判定は文字を SJIS と SJIS-win にそれぞれエンコードして、その結果の文字列を比較して行っています。
以下のクラスのインスタンスを作成して、文字列を与えて処理する形です。
class ExternalString
{
private $_encoding = 'UTF-8';
/**
* 外字インスタンスの配列
* @var array
*/
private $_externalCharacters;
/**
* コンストラクタ
* 文字列をセットすると外字インスタンスの配列を作る
* @param string $string 文字列
*/
public function __construct($string = null) {
$this->_string = $string;
$this->_externalCharacters = $this->_partStringAndJudgeExternal($string);
}
/**
* 文字列をセットするついでに外字インスタンスの配列を作る
* @param string $string
*/
public function setString($string) {
$this->_externalCharacters = $this->_partStringAndJudgeExternal($string);
}
/**
* 文字列を文字に分解して外字インスタンスをつくり、その配列として返す
* @param string $string
*/
private function _partStringAndJudgeExternal($string) {
$chars = array();
$length = mb_strlen($string, $this->_encoding);
for ($i = 0; $i < $length; $i++) {
$char = mb_substr($string, $i, 1, $this->_encoding);
$exChar = new ExternalCharacter($char);
$external = strcmp(mb_convert_encoding($char, 'SJIS', $this->_encoding), mb_convert_encoding($char, 'SJIS-win', $this->_encoding)) !== 0;
$exChar->setExternal($external);
$chars[$i] = $exChar;
}
return $chars;
}
/**
* 外字を取り除く
* @return array
*/
public function filter() {
return $this->_getEitherChars(false);
}
/**
* 外字だけ返す
* @return array
*/
public function pickup() {
return $this->_getEitherChars(true);
}
/**
* 外字か通常の文字かのどちらかを配列として返す
* @param boolean $external
* @return array
*/
private function _getEitherChars($external) {
$chars = array();
foreach ($this->_externalCharacters as $key => $exChar) {
if ($exChar->isExternal() === $external) {
$chars[] = $exChar->getCharacter();
}
}
return $chars;
}
/**
* 外字に色(のスタイル)を付けて文字列として返す
* @param string $color
* @return string
*/
public function getColoredString($color = '#ffff00') {
if (preg_match('/^#[0-9a-f]{6}$/', $color) == 0) {
$color = '#ffff00';
}
$chars = array();
foreach ($this->_externalCharacters as $key => $exChar) {
$char = htmlspecialchars($exChar->getCharacter());
if ($exChar->isExternal()) {
$char = '<span style="background-color: ' . $color . ';">' . $char . '</span>';
}
$chars[] = $char;
}
$string = implode('', $chars);
return $string;
}
}
class ExternalCharacter
{
/**
* 文字
* @var string
*/
private $_character;
/**
* 外字フラグ
* @var boolean
*/
private $_external;
/**
* コンストラクタ
* @param string $character
*/
public function __construct($character = null) {
$this->_character = $character;
$this->_external = false;
}
/**
* 文字setter
* @param string $character
*/
public function setCharacter($character) {
$this->_character = $character;
}
/**
* 外字フラグsetter
* @param boolean $external
*/
public function setExternal($external) {
$this->_external = $external;
}
/**
* 文字getter
* @return string
*/
public function getCharacter() {
return $this->_character;
}
/**
* 外字かどうかを言う
* @return boolean
*/
public function isExternal() {
return $this->_external;
}
}
あとは以下のようにして文字を処理して取り出しています。
$xStr = new ExternalString($string); // インスタンス生成
$coloredString = $xStr->getColoredString(); // 色付き文字列
$regularString = implode("", $xStr->filter()); // 機種依存文字除く文字
$externalString = implode("", $xStr->pickup()); // 機種依存文字
※ソース・コメントはもっといい書き方があれば修正すると思います。(文字列で返すか配列で返すかというところもそのうち。)