如何在PHP中读取Unicode文本文件?

5

我在PHP脚本中读取一个Unicode UTF16-LE格式的文本文件时遇到了一些困难。

我的PHP脚本保存为UTF-8格式(由于某些原因)。

以下是我的代码:

$lines = file("./somedir/$filename");

for ($i=0; $i < count($lines); $i++) {
    $lines[$i] = iconv("Unicode", "UTF-8", $lines[$i]); // converting to UTF8
}

echo "[0]:".$lines[0]; // outputs CORRECT text (like "This is the first line")
echo "[1]:".$lines[1]; // outputs something like çæ¤ææ¬çææ¸ææ°ã

有什么想法吗? 我检查了count($lines)的值,它是完全正确的... 谢谢。

编辑:
好的,所以我尝试了iconv("UTF-16", "UTF-8", $lines[$i]);
我还尝试了iconv("UTF-16LE", "UTF-8", $lines[$i]);
但仍然没有成功...


2
"Unicode"不是一种编码,你不能将文本保存在"Unicode"中,只能采用特定的Unicode编码(其中包括UTF-8)。 - Quentin
@Quentin 好的!我已经将它保存为UTF16-LE格式。但是由于我在PHP手册(File()函数)中没有找到编码列表,所以我选择了“Unicode” :) 那我应该填什么呢? - Enriqe
1
@Enriqe:如果你通过他人的评论发现你的问题缺少一些重要信息,不仅要在评论中添加该信息,还要编辑你的问题。 - hakre
2
在UTF-16中,行尾是0x000A,而在UTF-8中是0x0A。file()函数可能会在0x0A处分割,留下0x00,这将使所有字节左移一个字节,因此每隔一行输出垃圾。在拆分行之前,您应该将文件转换为utf-8或使用多字节扩展。是的,我不明白为什么这个问题被关闭。我投票支持重新开放。 - iblue
@hakre 好的,我删掉了那个抱怨。我只是因为没有得到有用的帮助而感到不满,并且由于未知原因而遭受了一些负评...谢谢。 - Enriqe
显示剩余5条评论
3个回答

13

PHP的file函数无法读取UTF-16LE编码的文件。它需要在换行符上分割,但是PHP仅支持单字节序列,在此处与多字节可变长度编码的UTF-16LE不兼容,因此不能使用file函数。

所以您正在使用错误的函数。这就是简单的答案。问题不在于iconv,而在于使用file

相反,您需要将文件读入缓冲区,从缓冲区逐行获取内容,然后对其进行重新编码为UTF-8。

首先要了解该文件中使用的行分隔符。由于PHP的文件函数(以及字符串函数和字符串本身)是基于二进制的,请使用二进制序列形式的stringstrpos函数来定位它。

然后,逐行从缓冲区中分离出来(如果缓冲区的字节用完了,则从文件中重新填充缓冲区),然后你可以按照手册页面中概述的方法使用iconv(或者你的问题,你拥有的示例代码看起来没有问题,只需注意使用正确的参数以确保编码正确)。

7
以下代码对我有效:
只需使用以下函数fopen_utf8而不是fopen。
<?php
# http://www.practicalweb.co.uk/blog/2008/05/18/reading-a-unicode-excel-file-in-php/
function fopen_utf8($filename){
    $encoding='';
    $handle = fopen($filename, 'r');
    $bom = fread($handle, 2);
//  fclose($handle);
    rewind($handle);

    if($bom === chr(0xff).chr(0xfe)  || $bom === chr(0xfe).chr(0xff)){
            // UTF16 Byte Order Mark present
            $encoding = 'UTF-16';
    } else {
        $file_sample = fread($handle, 1000) + 'e'; //read first 1000 bytes
        // + e is a workaround for mb_string bug
        rewind($handle);

        $encoding = mb_detect_encoding($file_sample , 'UTF-8, UTF-7, ASCII, EUC-JP,SJIS, eucJP-win, SJIS-win, JIS, ISO-2022-JP');
    }
    if ($encoding){
        stream_filter_append($handle, 'convert.iconv.'.$encoding.'/UTF-8');
    }
    return  ($handle);
} 
?>

{{链接1:从这个网站}}


-2

以下是我用来将Unicode转换为普通文本格式的代码。

function ReadUnicodeFile($fn)    
  $fc = "";    
  $fh = fopen($fn,"rb") or die("Cannot open file for read: $fn&lt;br&gt;\n");    
  $flen = filesize($fn);    
  $bc = fread($fh, $flen);

  for ($i=0; $i&lt;$flen; $i++){    
    $c = substr($bc,$i,1);    
    if ((ord($c) != 0) && (ord($c) != 13))    
      $fc = $fc . $c;    
  }

  if ((ord(substr($fc,0,1)) == 255) && (ord(substr($fc,1,1)) == 254))    
    $fc = substr($fc,2);    
  return ($fc);    
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接