[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 メーリングリストの案内