2010-03-05 29 views
5

tôi có chức năng sau đây từ trang php.net để xác định # byte trong một ASCII và UTF-8 chuỗi:Làm cách nào để tìm số byte trong chuỗi UTF-8 bằng PHP?

<?php 
/** 
* Count the number of bytes of a given string. 
* Input string is expected to be ASCII or UTF-8 encoded. 
* Warning: the function doesn't return the number of chars 
* in the string, but the number of bytes. 
* 
* @param string $str The string to compute number of bytes 
* 
* @return The length in bytes of the given string. 
*/ 
function strBytes($str) 
{ 
    // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT 

    // Number of characters in string 
    $strlen_var = strlen($str); 

    // string bytes counter 
    $d = 0; 

/* 
    * Iterate over every character in the string, 
    * escaping with a slash or encoding to UTF-8 where necessary 
    */ 
    for ($c = 0; $c < $strlen_var; ++$c) { 

     $ord_var_c = ord($str{$d}); 

     switch (true) { 
      case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): 
       // characters U-00000000 - U-0000007F (same as ASCII) 
       $d++; 
       break; 

      case (($ord_var_c & 0xE0) == 0xC0): 
       // characters U-00000080 - U-000007FF, mask 110XXXXX 
       // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
       $d+=2; 
       break; 

      case (($ord_var_c & 0xF0) == 0xE0): 
       // characters U-00000800 - U-0000FFFF, mask 1110XXXX 
       // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
       $d+=3; 
       break; 

      case (($ord_var_c & 0xF8) == 0xF0): 
       // characters U-00010000 - U-001FFFFF, mask 11110XXX 
       // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
       $d+=4; 
       break; 

      case (($ord_var_c & 0xFC) == 0xF8): 
       // characters U-00200000 - U-03FFFFFF, mask 111110XX 
       // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
       $d+=5; 
       break; 

      case (($ord_var_c & 0xFE) == 0xFC): 
       // characters U-04000000 - U-7FFFFFFF, mask 1111110X 
       // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
       $d+=6; 
       break; 
      default: 
      $d++;  
     } 
    } 

    return $d; 
} 
?> 

Tuy nhiên khi tôi thử điều này với Nga (ví dụ По своей природе компьютеры могут работать лишь с числами. И для того, чтобы они могли хранить в памяти буквы или другие символы, каждому такому символу должно быть поставлено в соответствие число.). Nó dường như không trả về số byte đúng.

Tuyên bố chuyển đổi đang sử dụng điều kiện mặc định. Bất kỳ ý tưởng nào tại sao các nhân vật Nga sẽ không hoạt động như mong đợi? Hoặc sẽ có lựa chọn tốt hơn cho việc này.

Tôi yêu cầu điều này vì tôi cần phải rút ngắn chuỗi UTF-8 thành một số byte nhất định. tức là tôi chỉ có thể gửi giá thầu CPC trong số 169 byte dữ liệu JSON tới APNS của iPhone trong tình huống của tôi (không bao gồm dữ liệu gói khác).

tham khảo: PHP strlen - Manual (Paolo Comment on 10-Jan-2007 03:58)

+5

chuyển đổi (đúng)? Đó là một cách kỳ lạ để làm việc .. –

+0

Chức năng là từ các bình luận trong tài liệu tham khảo ở dưới cùng của bài viết. Tôi đã không mã nó :) Tuy nhiên có vẻ như nó là đúng quá trình chứ không phải là sử dụng mb_strlen, ngoài các ký tự tiếng Nga không làm việc. – Luke

+0

@Brendan Tôi chỉ đang nghĩ như vậy. – alex

Trả lời

1

Nếu bạn muốn tìm độ dài byte của một chuỗi đa byte khi bạn đang sử dụng mbstring.func_overload 2 và UTF-8 chuỗi, sau đó bạn có thể sử dụng như sau:

mb_strlen($utf8_string, 'latin1'); 
+0

Điều này không chỉ cho độ dài chuỗi trong số ký tự? Tôi cần phải biết số byte thực tế đang được sử dụng. Trong utf-8, một ký tự có thể nhiều hơn một byte, đúng không? – Luke

+0

theo phần bình luận của http://php.net/manual/en/function.mb-strlen.php (rất dưới), nó được đồng ý rộng rãi rằng chức năng này được gọi theo cách mô tả sẽ đếm BYTES. khi bạn cho biết hàm, chuỗi đầu vào của bạn chứa ký tự latin1 (ergo: ascii), anh ấy có thể đếm từng byte dưới dạng ký tự, mặc dù nó có thể không phải là ký tự hợp lệ theo nghĩa ascii. bạn có thể thử điều này không? tôi lo lắng không có một môi trường hỗ trợ mb ... –

1

Trong PHP 5, mb_strlen phải trả về số ký tự; và strlen phải trả lại số byte.

Ví dụ, phần mã này:

$string = 'По своей природе компьютеры могут работать лишь с числами. И для того, чтобы они могли хранить в памяти буквы или другие символы, каждому такому символу должно быть поставлено в соответствие число'; 
echo mb_strlen($string, 'UTF-8') . '<br />'; 
echo strlen($string); 

nên giúp bạn có được kết quả như sau:

196 
359 


Là một sidenote: đây là một trong những những điều mà PHP 6 sẽ thay đổi : PHP 6 sẽ được sử dụng Unicode theo mặc định, có nghĩa là strlen nên, trong PHP 6, trả về số lượng ký tự, và không phải là một số byte nữa.

+0

Ngay cả với PHP5 đó không phải là một giả định bạn có thể thực hiện. strlen() có thể hoặc không bị quá tải bởi mb_strlen(). Đó là an toàn hơn chỉ để gọi mb_strlen ($ string, 'latin1'); – Xorlev

+0

Chức năng tôi đã cung cấp trong câu hỏi dường như hoạt động tốt đối với utf-8. Tôi tin rằng vấn đề với vấn đề của tôi là ở một nơi khác trong mã PUSH APNS của iPhone. Tôi dường như có thể PUSH khoảng 160 byte của tiếng Nhật, tiếng Anh văn bản vv Tuy nhiên tôi chỉ có thể PUSH khoảng 110 byte của ký tự Cyrillic (Nga). – Luke

+0

Tôi vẫn tin rằng strlen và mb_strlen không thể dựa vào để xác định các byte thực tế. – Luke

2

strlen() trả về số byte.

Rút ngắn chuỗi nhiều byte thành một số byte nhất định là một tác vụ riêng biệt. Bạn sẽ cần phải cẩn thận không để cắt chuỗi ở giữa một chuỗi multibyte khi bạn rút ngắn nó.

Điều khác bạn cần xử lý là khi bạn đặt một chuỗi ký tự vào ký hiệu json, nó có thể cần nhiều byte hơn để biểu diễn nó như là json. Ví dụ: nếu chuỗi của bạn chứa ký tự ngoặc kép. Nó cần phải được thoát, và ký tự dấu gạch chéo ngược sẽ thêm một byte. Có những nhân vật khác cũng cần phải trốn thoát. Điểm là, nó có thể lớn hơn. Tôi giả định giới hạn byte là trên tổng trọng tải json, vì vậy bạn cần phải tính đến cú pháp json, cũng như bất kỳ thoát nào mà json sẽ áp đặt lên chuỗi của bạn.

Cách thức hack không được tối ưu hóa, tốt nhất để làm điều đó là cắt chuỗi, với giới hạn 5 byte nhiều hơn giới hạn của bạn, sử dụng substr(). Bây giờ sử dụng mb_strlen() để lấy số ký tự và mb_substr() để xóa ký tự cuối cùng. Bây giờ mã hóa nó thành json và đo byte thông qua strlen(). Nhập một vòng lặp, mà giữ chặt ra ký tự cuối cùng bằng cách sử dụng mb_substr(), mã hóa như json, và một lần nữa đo byte bằng cách sử dụng strlen(). Vòng lặp kết thúc khi số byte được chấp nhận.

+0

Tôi đã có một vòng lặp trong khi giữ chặt 1 ký tự cùng một lúc bằng cách sử dụng mb_substr cho đến khi các byte giảm xuống dưới giới hạn. strlen, dường như không trả về cùng số byte như hàm trong câu hỏi của tôi. strlen() có thể hoặc không thể bị quá tải bởi mb_strlen() theo các bình luận khác, do nó không nên dựa vào. – Luke

+0

Vì vậy, đừng quá tải strlen. Nếu bạn không kiểm soát nó, thì có những cách khác. Ví dụ: while (isset ($ str [$ i])) $ i ++; sẽ làm các trick. Hoặc fwrite() nó vào một dòng hoặc một cái gì đó ... – goat

3

Tôi yêu cầu điều này vì tôi cần rút ngắn chuỗi utf-8 thành một số lượng nhất định là byte.

mb_strcut() thực hiện chính xác điều này, mặc dù bạn có thể không biết được tài liệu khó hiểu.

+0

Cảm ơn bạn, bằng cách sử dụng mb_strcut() là tốt hơn so với mb_substr() cho tình hình của tôi. – Luke

0

Số lượng byte = <> Độ dài chuỗi!

để nhận số byte bạn có thể sử dụng (php4,5) strlen. để có được chuỗi unicode (utf8 mã hóa) chiều dài, bạn có thể sử dụng mb_strlen (chăm sóc về chức năng quá tải từ phần mở rộng đó) hoặc bạn có thể chỉ cần đếm tất cả các byte mà không có bộ bit 8.

Phương tiện bit thứ 8 có nghĩa là đối với unicodechar này sẽ có ít nhất một byte nữa từ đầu vào.

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