PHPで機種依存文字判定ツールを作ってみた

 PHP  コメントは受け付けていません。
11月 302011
 

近年は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()); // 機種依存文字

※ソース・コメントはもっといい書き方があれば修正すると思います。(文字列で返すか配列で返すかというところもそのうち。)

参考サイト:
Windowsの機種依存文字
PHP で機種依存文字をフィルタリングする関数を作ってみた | ウェブル
floatingdays: PHPの SJISと SJIS-WINの違い
 Posted by at 12:10 AM