2012-03-14 44 views
5

Tôi đã tìm thấy một chức năng hữu ích trên một câu trả lời khác và tôi tự hỏi nếu ai đó có thể giải thích cho tôi những gì nó đang làm và nếu nó là đáng tin cậy. Tôi đã sử dụng mb_detect_encoding() nhưng nó đã không được khắc phục khi đọc từ một tập tin ISO8859-1 trên một hệ điều hành Linux.Kiểm tra chuỗi UTF8 trong PHP, đây có phải là phương pháp đáng tin cậy không?

Chức năng này có vẻ hoạt động trong mọi trường hợp tôi đã thử nghiệm.

Đây là câu hỏi: Get file encoding

Dưới đây là các chức năng:

function isUTF8($string){ 
    return preg_match('%(?: 
    [\xC2-\xDF][\x80-\xBF]        # non-overlong 2-byte 
    |\xE0[\xA0-\xBF][\x80-\xBF]               # excluding overlongs 
    |[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}      # straight 3-byte 
    |\xED[\x80-\x9F][\x80-\xBF]               # excluding surrogates 
    |\xF0[\x90-\xBF][\x80-\xBF]{2}    # planes 1-3 
    |[\xF1-\xF3][\x80-\xBF]{3}                  # planes 4-15 
    |\xF4[\x80-\x8F][\x80-\xBF]{2}    # plane 16 
   )+%xs', $string); 
} 

Đây có phải là một cách đáng tin cậy phát hiện chuỗi UTF8? Chính xác nó đang làm gì? Nó có thể được thực hiện mạnh mẽ hơn?

+2

Tại sao không sử dụng một cái gì đó như 'mb_detect_encoding' (http: // php .net/manual/en/function.mb-detect-encoding.php)? – summea

+1

Chỉ cần đề cập đến chức năng này cho rằng chuỗi "1" không phải là utf8, trong khi đó (phải rõ ràng nó chỉ là một ascii, nhưng nó vẫn nên được kết hợp thành utf8) – zerkms

+0

@summea bạn đã đọc câu hỏi chưa tất cả các? –

Trả lời

6

Nếu bạn không biết mã hóa chuỗi, bạn không thể đoán mã hóa với bất kỳ mức độ chính xác nào. Đó là lý do tại sao mb_detect_encoding chỉ đơn giản là không hoạt động. Tuy nhiên, nếu bạn biết mã hóa chuỗi nên là gì, bạn có thể kiểm tra xem chuỗi đó có phải là chuỗi hợp lệ trong mã hóa đó hay không bằng cách sử dụng mb_check_encoding. Nó ít nhiều làm những gì regex của bạn làm, có lẽ là một chút toàn diện hơn. Nó có thể trả lời câu hỏi "Chuỗi byte này có hợp lệ trong UTF-8 không?" có chữ rõ ràng hoặc không. Điều đó không nhất thiết có nghĩa là chuỗi thực sự được mã hóa trong mã hóa đó, chỉ có thể là chuỗi đó. Ví dụ, nó sẽ không thể phân biệt bất kỳ mã hóa byte đơn nào sử dụng tất cả 8 bit từ bất kỳ mã hóa byte đơn nào khác sử dụng 8 bit. Nhưng UTF-8 nên có thể phân biệt được, mặc dù bạn có thể sản xuất, ví dụ, các chuỗi được mã hóa bằng Latin-1 cũng xảy ra là các chuỗi byte UTF-8 hợp lệ.

Tóm lại, không có cách nào để biết chắc chắn. Nếu bạn mong đợi UTF-8, hãy kiểm tra xem chuỗi byte bạn nhận được có hợp lệ trong UTF-8 không, thì bạn có thể xử lý chuỗi an toàn như UTF-8. Ngoài ra, hầu như không có bất cứ điều gì bạn có thể làm.

+0

Tôi có thể kiểm tra xem chuỗi có phải là chuỗi UTF-8 hợp lệ hay không, nhưng "Hello World" cũng sẽ vượt qua bài kiểm tra đó ngay cả khi nó ở dạng ASCII, nhưng bạn có thể xác thực theo cách sẽ cho bạn biết đó có phải là latin hợp lệ không -1 hoặc ascii, và KHÔNG phải là UTF-8? –

+1

"Hello World" là hợp lệ ASCII * và * Latin-1 * và * UTF-8! – deceze

+0

Tôi nhận được xung quanh nó bằng cách kiểm tra nó nếu là một UTF-8, nếu nó là và sau đó nó không kiểm tra cho một ASCII hợp lệ, tôi giả định nó là ASCII, khác nó là một UTF-8. Tôi cần điều này vì tôi cần đặt cờ trong cấu trúc tiêu đề tệp Zip nếu nó là một UTF-8, nhưng không nên làm điều này nếu nó không phải là. –

0

Vâng, nó chỉ kiểm tra xem chuỗi có chuỗi byte xảy ra tương ứng với các điểm mã UTF-8 hợp lệ hay không. Tuy nhiên, nó sẽ không gắn cờ chuỗi 0x00-0x7F là tập hợp con tương thích ASCII của UTF-8.

EDIT: Ngẫu nhiên tôi đoán lý do suy nghĩ mb_detect_encoding() "không hoạt động đúng" là vì tệp được mã hóa Latin-1 của bạn chỉ sử dụng tập con tương thích ASCII, cũng hợp lệ trong UTF-8. Không có gì ngạc nhiên khi mb_detect_encoding() sẽ gắn cờ là UTF-8 và nó là "đúng", nếu dữ liệu chỉ là ASCII đơn giản thì câu trả lời UTF-8 tốt bằng Latin-1 hoặc ASCII hoặc bất kỳ ASCII mở rộng vô hạn nào mã hóa.

+0

Vấn đề là tôi cần phải làm thêm mã hóa vì vậy tôi cần phải biết chính xác những gì nó là trước khi tôi mã hóa nó một lần nữa. Và có, đó là vấn đề với bộ ASCII mở rộng. –

0

Điều đó sẽ chỉ phát hiện nếu một phần của chuỗi là chuỗi UTF-8 hợp lệ chính thức, bỏ qua một ký tự mã hóa đơn vị mã (đại diện cho các điểm mã trong ASCII). Để hàm đó trả về true, nó đủ để có một ký tự trông giống như một ký tự mã hóa UTF-8 không phải ASCII.

0

Đây có thể không phải là câu trả lời cho câu hỏi của bạn (có thể là, xem cập nhật bên dưới), nhưng đó có thể là câu trả lời cho vấn đề của bạn.Kiểm tra lớp Encoding tôi có phương pháp để chuyển đổi xâu kí tự sang UTF8, không có vấn đề nếu chúng được mã hóa trong latin1, Win1252, hoặc UTF8 đã có, hoặc một kết hợp của chúng:

Encoding::toUTF8($text_or_array); 
Encoding::toWin1252($text_or_array); 
Encoding::toISO8859($text_or_array); 

// fixes UTF8 strings converted to UTF8 repeatedly: 
// "FÃÂédÃÂération" to "Fédération" 
Encoding::fixUTF8($text_or_array); 

https://stackoverflow.com/a/3479832/290221

Chức năng chạy byte theo byte và tìm ra nếu mỗi người trong số họ cần chuyển đổi hay không.

Cập nhật:

Suy nghĩ một chút về nó, điều này có thể trên thực tế là câu trả lời cho câu hỏi của bạn:

require_once('Encoding.php'); 

function validUTF8($string){ 
    return Encoding::toUTF8($string) == $string; 
} 

Và đây là lớp Encoding: https://github.com/neitanod/forceutf8

+0

Điều đó chỉ có thể làm việc trên cơ sở đoán đúng nhất. Nếu tôi * có nghĩa là * để viết "FÃÂÃÂ © dÃÂÃÂ © ration"? Giống như trên trang này rất ở đây để chứng minh vấn đề mã hóa. Nếu bạn đã sửa đổi văn bản do mã hóa phương pháp điều trị sai, bạn cần phải sửa chữa các phương pháp điều trị sai, chứ không phải văn bản. – deceze

+0

Chính xác. Đó là lý do tại sao chức năng cuối cùng được tách ra thành TOF8(), thành chức năng riêng của nó. Tôi đã sửa fixUTF8() để sửa một số tệp bằng chương trình dòng lệnh. Nó không dành cho các trang web trực tiếp. Tuy nhiên, tôi KHÔNG sử dụng toUTF8() trên các trang web trực tiếp. –

+0

Tôi cũng không thực sự hiểu sự cần thiết phải kiểm tra từng byte riêng lẻ. Bạn có mong đợi các chuỗi được mã hóa hỗn hợp không? Nếu vậy, vấn đề của bạn là ở nơi khác. Mã hóa có tính chất như vậy mà bạn thực sự cần * biết * những gì bạn đang xử lý. Bạn không thể coi chuỗi là hộp đen, bạn chỉ có thể chuyển đổi * từ * một mã hóa * sang * một mã khác. Nếu không biết điều này * từ * là bạn không thể nhận được kết quả mà bạn đang tìm kiếm một cách đáng tin cậy. Trong khi lớp học của bạn khá là một phần công việc, tôi thực sự khuyên bạn nên sử dụng nó. – deceze

0

Về cơ bản , không.

  • Bất kỳ UTF8 chuỗi là một chuỗi mã hóa 8-bit có giá trị (ngay cả khi nó tạo ra vô nghia).
  • Mặt khác, nhất 8-bit mã hóa chuỗi với (128+) ký tự mở rộng là không hợp lệ UTF8, nhưng, như bất kỳ chuỗi byte ngẫu nhiên khác, họ có thể xảy ra được.
  • Và, của người phối ngẫu, bất kỳ văn bản ASCII nào hợp lệ UTF8, vì vậy, trên thực tế, đúng là bằng cách nói như vậy. Và không, bạn sẽ không gặp bất kỳ vấn đề nào khi sử dụng văn bản ASCII như UTF8. Đó là lý do UTF8 hoạt động ngay từ đầu.

Theo như tôi hiểu, hàm bạn cung cấp không kiểm tra hiệu lực của chuỗi, chỉ là nó có chứa một số chuỗi điều đó xảy ra là tương tự như của UTF8, do đó chức năng này có thể đạn không nổ tồi tệ hơn nhiều . Bạn có thể muốn sử dụng cả hai chức năng này mb_detect_encoding ở chế độ nghiêm ngặt và hy vọng rằng chúng sẽ loại bỏ từng kết quả dương tính sai khác.

Nếu văn bản được viết bằng bảng chữ cái không phải latin, cách "thông minh" để phát hiện mã hóa nhiều byte là tìm chuỗi các byte có kích thước bằng nhau bắt đầu bằng cùng một bit. Ví dụ: từ tiếng Nga "привет" trông giống như sau:

11010000 10111111 
11010001 10000000 
11010000 10111000 
11010000 10110010 
11010000 10110101 
11010001 10000010 

Điều này, tuy nhiên, sẽ không hoạt động cho bảng chữ cái gốc Latinh (và, có thể là tiếng Trung).

0

Chức năng trong câu hỏi (một trong đó người sử dụng pilif đăng trong câu hỏi liên quan) dường như đã được lấy từ this comment trên mb_detect_encoding() trang trong Manual PHP:

Theo các tiểu bang tác giả, chức năng duy nhất là có nghĩa là "kiểm tra xem một chuỗi có chứa ký tự UTF-8 không" và nó chỉ tìm kiếm "chuỗi đa byte không ascii trong phạm vi UTF-8". Do đó, hàm trả về false (không thực sự) nếu chuỗi của bạn chỉ chứa các ký tự ascii đơn giản (như văn bản tiếng Anh), có lẽ không phải là những gì bạn muốn.

Chức năng của ông được dựa trên một chức năng khác trong this previous comment trên cùng một trang đó, trên thực tế, có nghĩa là để kiểm tra xem một chuỗi là UTF-8 và dựa trên this regular expression được tạo bởi ai đó tại W3C.

Đây là bản gốc, một cách chính xác làm việc (tôi đã thử nghiệm) chức năng sẽ cho bạn biết nếu một chuỗi là UTF-8:

// Returns true if $string is valid UTF-8 and false otherwise. 
function is_utf8($string) { 

    // From http://w3.org/International/questions/qa-forms-utf-8.html 
    return preg_match('%^(?: 
      [\x09\x0A\x0D\x20-\x7E]   # ASCII 
     | [\xC2-\xDF][\x80-\xBF]    # non-overlong 2-byte 
     | \xE0[\xA0-\xBF][\x80-\xBF]  # excluding overlongs 
     | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte 
     | \xED[\x80-\x9F][\x80-\xBF]  # excluding surrogates 
     | \xF0[\x90-\xBF][\x80-\xBF]{2}  # planes 1-3 
     | [\xF1-\xF3][\x80-\xBF]{3}   # planes 4-15 
     | \xF4[\x80-\x8F][\x80-\xBF]{2}  # plane 16 
    )*$%xs', $string); 

} // function is_utf8 
+0

Nhân tiện, một vấn đề khi sử dụng 'mb_detect_encoding()' là nó không hỗ trợ bộ ký tự "Mac OS Roman" (hoặc "macintosh"), vẫn được sử dụng phổ biến trên OS X. Nó sẽ xác định không đúng như UTF-8. – jnrbsn

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