2010-09-26 13 views
8

Digamos que tengo un archivo llamado foo.txt codificado en UTF-8:Trabajar con archivos y UTF-8 en PHP

aoeu 
qjkx 
ñpyf 

y quiero obtener una matriz que contiene todas las líneas en el archivo (una línea por índice) que tienen las letras aoeuñpyf, y solo las líneas con estas letras.

I escribió el siguiente código (también codificado como 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); 

Sin embargo, después de eso, la matriz $lines sólo tiene la línea aoeu en ella.
Esto parece ser porque de alguna manera, la "ñ" en $allowed_letters no es lo mismo que la "ñ" en foo.txt.
También si imprimo una "ñ" del archivo, aparece un signo de interrogación, pero si lo imprimo así print "ñ";, funciona.
¿Cómo puedo hacer que funcione?

+2

Probablemente sus s "n" no son iguales: uno es un solo símbolo de la "ñ" y otra es [combinado de dos caracteres] (http://en.wikipedia.org/wiki/Unicode#Combining_characters) –

+0

No, ese no es el caso. Los teclados españoles tienen una tecla ñ y escriben un solo carácter. –

Respuesta

10

Si está ejecutando Windows, el sistema operativo no guarda los archivos en UTF-8, pero en cp1251 (o algo así ...) de forma predeterminada debe guardar el archivo en ese formato explícitamente o ejecutar cada línea en utf8_encode() antes realizando su cheque. Es decir .:

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

Si está seguro de que el archivo está codificado en UTF-8, es su archivo PHP también codificación UTF-8?

Si todo es UTF-8, entonces esto es lo que necesita:

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

(anexar u de caracteres Unicode)

Sin embargo, permítanme sugerir un modo aún más rápido para realizar su comprobar:

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

(añadir caracteres de espacio para permitir que los caracteres de espacio, así, y retire el rtrim($line))

+0

Woha, woha woha !!! ¡¡¡Eso funciono!!! (agregando el 'u', estoy ejecutando Linux). ¡Gracias! –

0

Parece que ya obtuvo su respuesta, pero es importante reconocer que los caracteres Unicode se pueden almacenar de múltiples maneras. La normalización Unicode * es un proceso que puede ayudar a asegurar que las comparaciones funcionen como se espera.

2

En UTF-8, ñ se codifica como dos bytes. Normalmente en PHP todas las operaciones de cadena están basadas en bytes, de modo que cuando preg_split la entrada se divide el primer byte y el segundo byte en elementos de matriz separados. Ni el primer byte en sí mismo ni el segundo byte en sí mismo coincidirán con los dos bytes como se encontró en $allowed_letters, por lo que nunca coincidirá con ñ.

Cuando Yanick publicó, la solución es agregar el modificador u. Esto hace que el motor de expresiones regulares de PHP trate el patrón y la línea de entrada como caracteres Unicode en lugar de bytes. Es una suerte que PHP tenga soporte especial para Unicode aquí; en otras partes, el soporte Unicode de PHP es extremadamente irregular.

Una manera más simple y rápida de dividir sería comparar cada línea con una expresión regular de un grupo de caracteres.Nuevamente, esto debe ser una expresión regex u.

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

+1 para una buena solución con preg_match() –