[PHP-users 21548]Re: 内部エンコードUTF8のファイルからUTF-16のCSVファイルを読み込む

UNO Shintaro uno @ venus.dti.ne.jp
2004年 5月 7日 (金) 00:14:53 JST


>  これまででお分かりのように、原因は行の読み込みに fgets を使っている
>せいです。UTF-16LE に対応した fgets などという便利なものはないので、自
>分で作るか別のアプローチを考えなければいけません。

アプローチを1つ考えて、コードを書いてみました。
ちょっとPHPのバージョンを選んでしまうのですけれど、
PHP4.3.2からの新機能であるstream_wrapper_registerを使って、
encoding変換プロトコルラッパを作るという方法です。

UTF-16LEのファイルをUTF-8で読み込む今回の例は、
たとえば次のような書き方でできるようになります。

require "MBConvertEncodingStreamWrapper.php";
stream_wrapper_register('mbconv', 'MBConvertEncodingStreamWrapper');

$fn = "mbconv://UTF=8:UTF-16LE:./aaa.txt";

$row = 0;
$fp = fopen($fn, 'r');
while($feof($fp)){
    $line = fgets($fp);
    $data[$row] = explode(',', $line);
    $row++;
}

あと、「Webサイトからデータを取得して、エンコーディングを自動認識して、
内部文字エンコーディングに変換して表示する」みたいな処理は、

print file_get_contents("mbconv://:auto:http://www.google.co.jp/");

で出来てしまいます。

このMBConvertEncodingStreamWrapper.phpのソースを下記に。
小山さんが書いてくださったコードをぱくって「一気に読み込んで変換」
方式なので、実行効率は良くないし、本来は色々考慮して盛り込むべき
ことがあるんですけれど、とりあえず素材提供ということで。


MBConvertEncodingStreamWrapper.php
--------------------------------------------------------
<?php
class MBConvertEncodingStreamWrapper {
    var $contents;
    var $currentPosition;

    function stream_open($path, $mode, $options, &$opened_path)
    {
        $p = strpos($path, '://');
        $s = substr($path, $p + 3);

        $p = strpos($s, ':');
        $targetEncoding = substr($s, 0, $p);
        $s = substr($s, $p + 1);

        $p = strpos($s, ':');
        $sourceEncoding = substr($s, 0, $p);
        $s = substr($s, $p + 1);

        $sourceContents = file_get_contents($s);
        if($sourceContents === false)
            return false;

        $this->contents = mb_convert_encoding($sourceContents,
            $targetEncoding, $sourceEncoding);

        $this->currentPosition = 0;
        return true;
    }

    function stream_read($count)
    {
        $ret = substr($this->contents, $this->currentPosition, $count);
        $this->currentPosition += strlen($ret);
        return $ret;
    }

    function stream_tell()
    {
        return $this->currentPosition;
    }

    function stream_eof()
    {
        return $this->currentPosition >= strlen($this->contents);
    }

    function stream_seek($offset, $whence)
    {
        switch($whence) {
            case SEEK_SET:
                $base = 0;
                break;

            case SEEK_CUR:
                $base = $this->currentPosition;
                break;

            case SEEK_END:
                $base = strlen($this->contents);
                break;

            default:
                return false;
        }

        $newPositionCandidate = $base + $offset;
        if ($newPositionCandidate < 0) return false;

        $this->currentPosition = $newPositionCandidate;
        return true;
    }
}
?>
--------------------------------------------------------

-- 
UNO Shintaro, 宇野 信太郎
mailto:uno @ venus.dti.ne.jp
http://www.venus.dti.ne.jp/~uno/


PHP-users メーリングリストの案内