2010-05-21 50 views
7

Tôi muốn phát hiện mã hóa của một số văn bản (sử dụng PHP). Vì mục đích đó, tôi sử dụng hàm mb_detect_encoding().Hành vi lạ của mb_detect_order() trong PHP

Vấn đề là hàm trả về các kết quả khác nhau nếu tôi thay đổi thứ tự mã hóa có thể bằng hàm mb_detect_order().

Hãy xem xét ví dụ sau

$html = <<< STR 
ちょっとのアクセスで落ちてしまったり、サーバー障害が多いレンタルサーバーを選ぶとあなたのビジネス等にかなりの影響がでてしまう可能性があります。特に商売をされている個人の方、法人の方は気をつけるようにしてください 
STR; 
mb_detect_order(array('UTF-8','EUC-JP', 'SJIS', 'eucJP-win', 'SJIS-win', 'JIS', 'ISO-2022-JP','ISO-8859-1','ISO-8859-2')); 
$originalEncoding = mb_detect_encoding($str); 
die($originalEncoding); // $originalEncoding = 'UTF-8' 

Tuy nhiên nếu bạn thay đổi thứ tự của bảng mã trong mb_detect_order() kết quả sẽ khác nhau:

mb_detect_order(array('EUC-JP','UTF-8', 'SJIS', 'eucJP-win', 'SJIS-win', 'JIS', 'ISO-2022-JP','ISO-8859-1','ISO-8859-2'));   
die($originalEncoding); // $originalEncoding = 'EUC-JP' 



Vì vậy, câu hỏi của tôi là:
Tại sao điều đó lại xảy ra?
Có cách nào trong PHP để phát hiện mã hóa văn bản một cách chính xác và rõ ràng không?

Trả lời

5

Đó là những gì tôi mong đợi sẽ xảy ra.

Thuật toán phát hiện có thể chỉ tiếp tục cố gắng, theo thứ tự, các mã hóa bạn đã chỉ định trong mb_detect_order và sau đó trả về giá trị đầu tiên theo đó byte gần nhất sẽ hợp lệ.

Điều gì đó thông minh hơn đòi hỏi phương pháp thống kê (tôi nghĩ máy học thường được sử dụng).

EDIT: Xem ví dụ: this article cho các phương pháp thông minh hơn.

Do tầm quan trọng của nó, tính năng phát hiện ký tự tự động đã được triển khai trong các ứng dụng Internet lớn như Mozilla hoặc Internet Explorer. Chúng rất chính xác và nhanh chóng, nhưng việc triển khai áp dụng nhiều kiến ​​thức cụ thể về miền trong từng trường hợp cụ thể. Trái ngược với phương pháp của họ, chúng tôi nhắm vào một thuật toán đơn giản có thể được áp dụng thống nhất cho mọi bộ ký tự và thuật toán dựa trên các kỹ thuật học máy tiêu chuẩn được thiết lập tốt. Chúng tôi cũng nghiên cứu mối quan hệ giữa phát hiện ngôn ngữ và bộ ký tự, và so sánh các thuật toán dựa trên byte và các thuật toán dựa trên ký tự. Chúng tôi đã sử dụng Naive Bayes (NB) và Hỗ trợ Vector Machine (SVM).

+0

cảm ơn bạn rất nhiều! – Termos

5

Không thực sự. Các mã hóa khác nhau thường có các vùng chồng chéo lớn và nếu chuỗi của bạn mà bạn đang kiểm tra tồn tại toàn bộ bên trong chồng chéo đó, thì cả hai mã hóa đều có thể chấp nhận được.

Ví dụ: utf-8 và ISO-8859-1 giống nhau đối với các chữ cái a-z. Chuỗi "hello" sẽ có chuỗi byte giống hệt nhau trong cả hai mã hóa.

Đây chính xác là lý do tại sao có chức năng mb_detect_order() ở vị trí đầu tiên vì nó cho phép bạn nói những gì bạn muốn xảy ra khi các sự cố này xảy ra. Bạn có muốn "hello" là utf-8 hoặc ISO-8859-1 không?

+0

Tôi cho rằng có rất nhiều biểu tượng trùng lặp trong 2 mã hóa khác nhau. Nếu có, làm cách nào tôi có thể chọn chế độ mã hóa phù hợp nhất với một số văn bản? Nói cách khác - "làm thế nào để tôi chọn một mã hóa sử dụng văn bản cụ thể nào có thể được mã hóa mà không mất bất kỳ dữ liệu nào"? – Termos

+0

Tôi sẽ chọn mã hóa linh hoạt nhất đầu tiên và cụ thể nhất cuối cùng. Vì vậy, tôi thích utf-8, vì nó sẽ mã hóa văn bản tiếng Nhật, cộng với tất cả các ngôn ngữ khác, trong khi một cái gì đó giống như ISO-8859-1 có vẻ phù hợp với một mẫu văn bản nhất định, nó sẽ gặp sự cố nếu bạn muốn thêm các ký tự không phải châu Âu. Thực sự, nếu bạn đang đối phó với rất nhiều bộ ký tự quốc tế khác nhau và bạn không biết họ sẽ làm gì trước, tại sao hãy thử và phát hiện tất cả - chỉ cần sử dụng thứ gì đó sẽ luôn hoạt động. –

1

mb_detect_encoding xem mục nhập ký tự đầu tiên trong mb_detect_order() của bạn và sau đó lặp qua ký tự kết hợp $ html đầu vào của bạn theo ký tự cho dù ký tự đó nằm trong bộ ký tự hợp lệ cho bộ ký tự. Nếu mọi ký tự khớp nhau, thì nó sẽ trả về true; nếu bất kỳ ký tự nào không thành công, nó sẽ chuyển sang bộ ký tự tiếp theo trong mb_detect_order() và thử lại.

The wikipedia list of charsets là một nơi tốt để xem các ký tự tạo nên mỗi bộ ký tự.

Vì các giá trị ký tự chồng lên nhau (char x8fA1EF tồn tại trong cả 'UTF-8' và trong 'EUC-JP'), đây sẽ được coi là kết hợp mặc dù nó là một ký tự hoàn toàn khác nhau trong mỗi bộ ký tự. Vì vậy, trừ khi bất kỳ giá trị ký tự nào tồn tại trong một bộ ký tự, nhưng không tồn tại trong một bộ ký tự khác, thì mb_detect_encoding không thể xác định bộ ký tự nào không hợp lệ; và sẽ trả lại bảng mã đầu tiên từ danh sách mảng của bạn có thể hợp lệ.

Theo như tôi biết, không có cách chắc chắn để xác định bảng mã. Phương pháp "đoán tốt nhất" của PHP có thể được trợ giúp nếu bạn có ý tưởng hợp lý về bộ ký tự bạn có khả năng gặp phải và sắp xếp danh sách của bạn cho phù hợp dựa trên khoảng trống (ký tự không hợp lệ) trong mỗi bộ ký tự. Giải pháp tốt nhất là "biết" bộ ký tự. Nếu bạn đang cạo html của mình từ một trang khác, hãy tìm mã định danh ký tự trong tiêu đề của trang đó.

Nếu bạn thực sự muốn thông minh, bạn có thể thử và xác định ngôn ngữ được viết html, có thể sử dụng trigram hoặc n-gram hoặc tương tự như được mô tả trong this article trên PHP/ir.

2

Lưu ý mb_detect_encoding() không biết mã hóa dữ liệu đang ở. Bạn có thể thấy một chuỗi, nhưng bản thân hàm chỉ thấy một luồng byte. Theo đó, nó cần phải đoán mã hóa là gì - ví dụ: ASCII sẽ là nếu byte chỉ trong phạm vi 0-127, UTF-8 sẽ là nếu có byte ASCII và 128+ byte chỉ tồn tại theo cặp hoặc nhiều hơn, v.v.

Như bạn có thể tưởng tượng, với bối cảnh đó, thật khó để phát hiện mã hóa một cách đáng tin cậy.

Giống như rihk cho biết, đây là chức năng mà mb_detect_order() dành cho - bạn về cơ bản là cung cấp phỏng đoán tốt nhất dữ liệu của bạn có khả năng là gì. Bạn có thường xuyên làm việc với các tệp UTF-8 không? Sau đó, rất có thể là nội dung của bạn không có khả năng là UTF-16 ngay cả khi mb_detect_encoding() có thể đoán được điều đó.

Bạn cũng có thể muốn xem Artefacto 's link để có chế độ xem chuyên sâu hơn.

Ví dụ trường hợp: Internet Explorer sử dụng một số mã hóa thú vị đoán nếu không có gì được quy định (@link Mục: 'Để tự động phát hiện ngôn ngữ của một trang web') đó là gây ra những hành vi kỳ lạ trên các trang web mà mất mã hóa cho các cấp trong quá khứ. Bạn có thể tìm thấy một số công cụ thú vị trên đó nếu bạn google xung quanh. Nó làm cho một trường hợp hiển thị tốt đẹp như thế nào thậm chí phương pháp thống kê có thể backfire khủng khiếp, và tại sao mã hóa-đoán nói chung là vấn đề.