2010-09-26 33 views
8

phép nói rằng tôi có một tập tin gọi là foo.txt mã hóa trong utf8:Làm việc với tập tin và utf8 trong PHP

aoeu 
qjkx 
ñpyf 

Và tôi muốn để có được một mảng chứa tất cả các dòng trong tập tin đó (một dòng cho mỗi chỉ số) có các chữ cái aoeuñpyf, và chỉ có các dòng với các chữ cái này.

tôi đã viết đoạn mã sau (cũng được mã hóa như là 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); 

Tuy nhiên, sau đó, các mảng $lines chỉ có dòng aoeu trong đó.
Điều này có vẻ là bởi vì bằng cách nào đó, "ñ" trong $allowed_letters không giống với "ñ" trong foo.txt.
Ngoài ra nếu tôi in một "ñ" của tệp, dấu chấm hỏi xuất hiện, nhưng nếu tôi in nó như thế này print "ñ";, nó hoạt động.
Tôi làm cách nào để hoạt động?

+2

Có thể các chữ "ñ" của bạn không bằng nhau: một là ký hiệu "ñ" và một ký tự khác [được kết hợp từ hai ký tự] (http://en.wikipedia.org/wiki/Unicode#Combining_characters). –

+0

Không, đó không phải là trường hợp. Bàn phím tiếng Tây Ban Nha có phím số và nó viết một ký tự đơn. –

Trả lời

10

Nếu bạn đang chạy Windows, hệ điều hành không lưu tệp bằng UTF-8, nhưng trong cp1251 (hoặc thứ gì đó ...) theo mặc định bạn cần lưu tệp ở định dạng đó một cách rõ ràng hoặc chạy từng dòng trong utf8_encode() trước thực hiện kiểm tra của bạn. I.e .:

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

Nếu bạn chắc chắn tệp được mã hóa UTF-8, tệp PHP của bạn có được mã hóa UTF-8 không?

Nếu mọi thứ đều là UTF-8, thì đây là những gì bạn cần:

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

(append u cho chars unicode)

Tuy nhiên, hãy để tôi đề xuất một cách chưa nhanh hơn để thực hiện của bạn kiểm tra:

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

(thêm ký tự dấu cách để cho phép ký tự khoảng trắng và xóa rtrim($line))

+0

Woha, woha woha !!! Điều đó đã làm việc !!! (phụ thêm 'u', tôi đang chạy Linux). Cảm ơn! –

0

Có vẻ như bạn đã có câu trả lời, nhưng điều quan trọng là phải nhận ra rằng các ký tự unicode có thể được lưu trữ theo nhiều cách. Unicode bình thường hóa * là một quá trình có thể giúp đảm bảo so sánh hoạt động như mong đợi.

2

Trong UTF-8, ñ được mã hóa như hai byte. Thông thường trong PHP tất cả các hoạt động chuỗi đều dựa trên byte, vì vậy khi bạn nhập một byte đầu tiên và byte thứ hai vào các byte mảng đầu tiên, thì đầu vào sẽ chia tách byte đầu tiên và byte thứ hai. Cả byte đầu tiên của chính nó cũng không phải byte thứ hai trên chính nó sẽ khớp cả hai byte với nhau như được tìm thấy trong $allowed_letters, vì vậy nó sẽ không bao giờ khớp với ñ.

Như Yanick đã đăng, giải pháp là thêm công cụ sửa đổi u. Điều này làm cho công cụ regex của PHP xử lý cả mẫu và dòng đầu vào dưới dạng ký tự Unicode thay vì byte. Thật may mắn khi PHP có hỗ trợ Unicode đặc biệt ở đây; ở đâu đó hỗ trợ Unicode của PHP cực kỳ nổi bật.

Cách đơn giản và nhanh hơn chia tách sẽ là so sánh từng dòng với regex nhóm ký tự.Một lần nữa, đây phải là một regex u.

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

+1 cho giải pháp tốt với preg_match() –

Các vấn đề liên quan