假设我有一个名为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 "ñ";
打印它,它就会起作用。
我怎样才能使它发挥作用?
答案 0 :(得分:10)
如果您运行的是Windows,则操作系统不会以UTF-8保存文件,但在cp1251(或其他...)中,默认情况下您需要以该格式显式保存文件或运行{{1中的每一行在执行检查之前。即:
utf8_encode()
如果您确定该文件是UTF-8编码的,那么您的PHP文件是否也是UTF-8编码的?
如果一切都是UTF-8,那么这就是你所需要的:
$line=utf8_encode(fgets($f));
(为{unicode chars附加foreach(preg_split("//u",$line,-1,PREG_SPLIT_NO_EMPTY) as $letter){
// ...
}
)
但是,让我建议一种更快捷的方式来执行检查:
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);
)
答案 1 :(得分:2)
在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;
答案 2 :(得分:0)
听起来你已经得到了答案,但重要的是要认识到unicode字符可以以多种方式存储。 Unicode规范化*是一个有助于确保比较按预期工作的过程。