【问题标题】:Working with files and utf8 in PHP在 PHP 中处理文件和 utf8
【发布时间】:2011-04-17 13:11:37
【问题描述】:

假设我有一个名为 foo.txt 的文件以 utf8 编码:

aoeu  
qjkx
ñpyf

我想得到一个数组,其中包含该文件中所有具有字母 aoeuñpyf 的行(每个索引一行),并且仅包含具有这些字母的行。

我写了以下代码(也编码为utf8):

$allowed_letters=array("a","o","e","u","ñ","p","y","f");

$lines=array();
$f=fopen("foo.txt","r");
while(!feof($f)){
    $line=fgets($f);
    foreach(preg_split("//",$line,-1,PREG_SPLIT_NO_EMPTY) as $letter){
        if(!in_array($letter,$allowed_letters)){
            $line="";
        }
    }
    if($line!=""){
        $lines[]=$line;
    }
}
fclose($f);

但是,在那之后,$lines 数组中只有 aoeu 行。
这似乎是因为不知何故,$allowed_letters 中的“ñ”与 foo.txt 中的“ñ”不同。
此外,如果我打印文件的“ñ”,则会出现一个问号,但如果我像这样print "ñ"; 打印它,它会起作用。
我怎样才能让它发挥作用?

【问题讨论】:

  • 可能您的“ñ”不相等:一个是单个“ñ”符号,另一个是combined from two characters
  • 不,事实并非如此。西班牙语键盘有一个 ñ 键,它只写一个字符。

标签: php file-io unicode utf-8


【解决方案1】:

如果您运行的是 Windows,操作系统不会将文件保存为 UTF-8,但默认情况下,您需要以 cp1251(或其他...)格式保存文件,或者在 utf8_encode() 中运行每一行在执行您的检查之前。即:

$line=utf8_encode(fgets($f));

如果您确定文件是 UTF-8 编码的,那么您的 PHP 文件是否也是 UTF-8 编码的?

如果一切都是 UTF-8,那么这就是你所需要的:

foreach(preg_split("//u",$line,-1,PREG_SPLIT_NO_EMPTY) as $letter){
   // ...
}

(为 unicode 字符附加 u

但是,让我建议一种更快的方法来执行您的检查:

$allowed_letters=array("a","o","e","u","ñ","p","y","f");

$lines=array();
$f=fopen("foo.txt","r");
while(!feof($f)){
    $line=fgets($f);

    $line = str_split(rtrim($line));
    if (count(array_intersect($line, $allowed_letters)) == count($line)) {
            $lines[] = $line;
    }
}
fclose($f);

(添加空格字符以允许空格字符,并删除rtrim($line)

【讨论】:

  • 哇哈哇哈!!!那行得通! (附加u,我正在运行Linux)。谢谢!
【解决方案2】:

听起来您已经有了答案,但重要的是要认识到 unicode 字符可以以多种方式存储。 Unicode 规范化* 是一个有助于确保比较按预期进行的过程。

【讨论】:

    【解决方案3】:

    在 UTF-8 中,ñ 被编码为两个字节。通常在 PHP 中所有字符串操作都是基于字节的,所以当你 preg_split 输入时,它会将第一个字节和第二个字节拆分为单独的数组项。第一个字节本身和第二个字节都不会像$allowed_letters 中的那样将两个字节匹配在一起,因此它永远不会匹配ñ

    正如 Yanick 所发布的,解决方案是添加 u 修饰符。这使得 PHP 的正则表达式引擎将模式和输入行都视为 Unicode 字符而不是字节。幸运的是 PHP 在这里有特殊的 Unicode 支持;在其他地方,PHP 的 Unicode 支持非常参差不齐。

    比拆分更简单、更快捷的方法是将每一行与字符组正则表达式进行比较。同样,这必须是 u 正则表达式。

    if(preg_match('/^[aoeuñpyf]+$/u', $line))
        $lines[]= $line;
    

    【讨论】:

      猜你喜欢
      • 2017-02-17
      • 1970-01-01
      • 1970-01-01
      • 2012-06-12
      • 1970-01-01
      • 2019-07-18
      • 1970-01-01
      • 2012-12-24
      • 1970-01-01
      相关资源
      最近更新 更多