2010-09-26 16 views
8

Diciamo che ho un file chiamato foo.txt codificato in utf8:Utilizzo di file e utf8 in PHP

aoeu 
qjkx 
ñpyf 

e voglio ottenere un array che contiene tutte le righe in quel file (una riga per indice) che hanno le lettere aoeuñpyf e solo le righe con queste lettere.

ho scritto il seguente codice (codificato anche come 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); 

Tuttavia, dopo che la matrice $lines ha solo la linea aoeu in esso.
Questo sembra essere perché in qualche modo, il "ñ" in $allowed_letters non è lo stesso di "ñ" in foo.txt.
Anche se stampo un "ñ" del file, viene visualizzato un punto interrogativo, ma se lo stampo come questo print "ñ";, funziona.
Come posso farlo funzionare?

+2

Probabilmente i vostri s "N" non sono uguali: uno è un simbolo singolo "N" e un altro è [combinato da due caratteri] (http://en.wikipedia.org/wiki/Unicode#Combining_characters). –

+0

No, non è così. Le tastiere spagnole hanno una chiave ñ e scrive un singolo carattere. –

risposta

10

Se si utilizza Windows, il sistema operativo non salva i file in UTF-8, ma in cp1251 (o qualcosa ...) per impostazione predefinita è necessario salvare il file in quel formato esplicitamente o eseguire ogni riga in utf8_encode() prima eseguendo il tuo assegno. Cioè .:

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

Se si è certi che il file è codifica UTF-8, è il file PHP anche codifica UTF-8?

Se tutto è UTF-8, allora questo è quello che vi serve:

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

(accoda u per i caratteri Unicode)

Tuttavia, vorrei suggerire un modo ancora più veloce per eseguire la CHECK:

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

(aggiungere caratteri di spazio per consentire caratteri spazio come bene, e rimuovere il rtrim($line))

+0

Woha, woha woha !!! Ha funzionato !!! (aggiungendo 'u', sto usando Linux). Grazie! –

0

Sembra che tu abbia già la risposta, ma è importante riconoscere che i caratteri Unicode possono essere memorizzati in diversi modi. La normalizzazione Unicode * è un processo che può aiutare a garantire che i confronti funzionino come previsto.

2

In UTF-8, ñ è codificato come due byte. Normalmente in PHP tutte le operazioni sulle stringhe sono basate su byte, quindi quando si usa l'input preg_split divide il primo byte e il secondo byte in elementi di array separati. Né il primo byte da solo né il secondo byte da solo corrisponderanno entrambi i byte insieme come trovato in $allowed_letters, quindi non corrisponderà mai a ñ.

Come ha annunciato Yanick, la soluzione è aggiungere il modificatore u. Questo fa sì che il motore regex di PHP tratti sia il pattern sia la riga di input come caratteri Unicode invece di byte. È fortunato che PHP abbia un supporto Unicode speciale qui; altrove il supporto Unicode di PHP è estremamente macchiato.

Un modo più semplice e più rapido della divisione sarebbe di confrontare ciascuna linea con un'espressione regolare del gruppo di caratteri.Ancora una volta, questa deve essere un'espressione regolare u.

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

+1 per una buona soluzione con preg_match() –