Работа с файлами и utf8 в PHP

Допустим, у меня есть файл с именем 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); в $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 » в $allowed_letters не совпадает с «ñ» в foo.txt.
Кроме того, если я печатаю «ñ» файла, появляется вопросительный знак, но если я печатаю его так, как это print "ñ"; , оно работает.
Как я могу заставить его работать?

Если вы используете 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){ // ... } 

(добавьте u для символов Unicode)

Однако позвольте мне предложить еще более быстрый способ выполнить ваш чек:

 $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); в $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) символы пробела, и удалите rtrim($line) )

В UTF-8, ñ кодируется как два байта. Обычно в PHP все строковые операции основаны на байтах, поэтому, когда вы preg_split ввода, он разбивает первый байт, а второй – на отдельные элементы массива. Ни первый байт самостоятельно, ни второй байты сами по себе не будут совпадать оба байта, как найдено в $allowed_letters , поэтому он никогда не будет соответствовать.

Как сказал Яник, решение заключается в добавлении модификатора u . Это заставляет PHP-регулярный механизм обрабатывать как шаблон, так и строку ввода как символы Unicode вместо байтов. Удачно, что PHP имеет специальную поддержку Unicode здесь; В другом месте поддержка Unicode от PHP является чрезвычайно пятнистой.

Более простым и быстрым способом, чем расщепление, было бы сравнение каждой строки с регулярным выражением группы символов. Опять же, это должно быть регулярное выражение.

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

Похоже, вы уже получили свой ответ, но важно признать, что символы Unicode могут храниться несколькими способами. Нормализация Юникода * – это процесс, который может помочь гарантировать, что результаты сопоставления будут работать, как ожидалось.