Работа с файлами и utf8 в PHP - PullRequest
8 голосов
/ 27 сентября 2010

Допустим, у меня есть файл с именем 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 "ñ";, он работает.
Как я могу заставить это работать?

Ответы [ 3 ]

10 голосов
/ 27 сентября 2010

Если вы работаете в 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 для символов Юникода)

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

$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))

2 голосов
/ 27 сентября 2010

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

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

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

if(preg_match('/^[aoeuñpyf]+$/u', $line))
    $lines[]= $line;
0 голосов
/ 27 сентября 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...