シフトJISの問題点

前口上

今のPHPにはシフトJISを使うための仕組みができています(デフォルトでは使えませんし,うちのサーバではその設定をしていません)。 もっとも,今は携帯でもEUC-JPに対応しているものが多いようですので,PHPではEUC-JPを使うのが最も安全でしょう。 将来的にはUTF-8のほうが好ましいでしょうけれど。

基本

携帯はシフトJISしか表示できないものが多いようですが,PHPの日本語部分にシフトJISを使うと問題が生じることがあります。

問題が生じうるのは次の文字です:

―ソЫ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹觸軆鐔饅鷭

これらの文字をシフトJISで表すと,2バイト目が半角の \ と同じコードになってしまいます。 PHPは(PerlやC言語でもそうですが)\ を特殊な意味に扱うことがあります。

たとえばシフトJISで

<?php echo "表"; ?>
<?php echo '表'; ?>

などと書くと, の2バイト目の \"' がくっついてしまって,エラーになります。

こんなときは

<?php echo "表\"; ?>
<?php echo '表\'; ?>

のように余分に \ を入れます。 あるいは

<?php echo '表 '; ?>
<?php echo '表 '; ?>

のように日本語の直後に半角文字(空白以外)が来ないようにするという手もあります。

HTMLは問題ありません。 シフトJISで

<img src="hyou.jpg" alt="表">

と書いてもかまいません。 これをPHPで書くと

<?php
  echo '<img src="hyou.jpg" alt="表">';
?>

または

<?php
  echo '<img src="hyou.jpg" alt="表\">';
?>

または

<?php
  echo "<img src=\"hyou.jpg\" alt=\"表\\">";
?>

となります。 この2番目の例では,シングルクォートの内側では \\\ と書いても同じであることを示しています。 シングルクォートの内側で特別扱いされるのは \\\ と同じ)と \'' と同じだが閉じの意味はない)だけです。

EUCからシフトJISへの変換

次のような簡単な関数を作れば変換できます。

  function euc2sj($x)
  {
    $y = "";
    $i = 0;
    while (($k = ord($x[$i++])) != 0) {
      if ($k < 0xa1) {
        if ($k == 0x8e) {
          if (($k = ord($x[$i++])) == 0) break;
        }
        $y .= chr($k);
      } else {
        if (($h = ord($x[$i++])) == 0) break;
        $k &= 0x7f;
        $h &= 0x7f;
        if ($k & 1) {
          if ($h < 0x60) $h += 0x1f;
          else           $h += 0x20;
        } else {
          $h += 0x7e;
        }
        if ($k < 0x5f) $k = ($k + 0xe1)  >> 1;
        else           $k = ($k + 0x161) >> 1;
        $y .= chr($k);
        $y .= chr($h);
      }
    }
    return $y;
  }

シフトJISでの全角→半角変換

受験番号など全角で入れられると困る番号・記号を半角数字・英大文字に統一します。

  function reg($x)
  {
    $y = "";
    $i = 0;
    while (($k = ord($x[$i++])) != 0) {
      if ($k == 0x82) {
        $k = ord($x[$i++]);
        if ($k == 0) break;
        if ($k >= 0x80) {
          $k -= 0x20;
        } else {
          $k -= 0x1f;
        }
      }
      if ($k >= 0x61) {
        $k -= 0x20;
      }
      if (($k >= 0x30 && $k <= 0x39) || ($k >= 0x41 && $k <= 0x5a)) {
        $y .= chr($k);
      }
    }
    return $y;
  }

奥村晴彦

Last modified: 2004-11-10 22:43:14