Допустим, у меня есть файл с именем 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 могут храниться несколькими способами. Нормализация Юникода * – это процесс, который может помочь гарантировать, что результаты сопоставления будут работать, как ожидалось.