Thử tìm hiểu mấy hàm có tiền tố mb (multibyte string) trong PHP giúp xử lý chuỗi tiếng Việt tốt hơn [phần 1]

Chế lại bánh xe là dở hơi, mất công, và kém hiệu quả. Ý tôi là việc viết các hàm mà PHP có thể có sẵn. Để dự phòng trường hợp đó, hôm nay tôi sẽ thử tìm hiểu mấy hàm xử lý chuỗi của PHP có hỗ trợ tiếng Việt cũng như hầu hết các ngôn ngữ không phải phương Tây khác.

  1. Hàm mb_substr

Hàm này dùng để cắt chuỗi. Cấu trúc của nó như sau:

mb_substr(
    string $string,
    int $start,
    ?int $length = null,
    ?string $encoding = null
): string
  • $string là chuỗi đầu vào;
  • int $start chỉ vị trí bắt đầu mà bạn muốn cắt. Nó cần là số nguyên, và là giá trị bắt buộc phải có; Vị trí của chuỗi bắt đầu từ 0. Ví dụ abcdef thì a có vị trí là 0, b có vị trí 1, f có vị trí 5.
  • $length chỉ độ dài ký tự muốn lấy, cũng cần là số nguyên;
  • $encoding chỉ mã hóa bạn muốn dùng, thường để là 'UTF-8';

Ví dụ:

echo mb_substr("Nguyễn Đức Anh", 1, 5, 'UTF-8');

// kết quả là guyễn

g ở vị trí số 1 (biến $start), lấy độ dài là 5 (biến $length), tức là đến n, do vậy ta có kết quả guyễn

'UTF-8' không cần chỉ định vẫn hoạt động được với tiếng Việt, vì khi đó PHP sẽ mặc định chọn bộ mã hóa mà $string đang dùng.

$length nếu không chỉ định sẽ lấy độ dài cực đại. Ví dụ:

echo mb_substr("Nguyễn Đức Anh", 2);

// cho kết quả uyễn Đức Anh

Tương tự nếu $length có giá trị lớn hơn độ dài còn lại của chuỗi, nó cũng sẽ lấy hết toàn bộ từ vị trí chỉ định đến cuối chuỗi.

Nếu $start có giá trị âm, nó sẽ lấy ngược từ cuối chuỗi, với số lượng ký tự là giá trị tuyệt đối của giá trị âm đó.

Ví dụ:

echo mb_substr("Nguyễn Đức Anh",-3);
// kết quả là Anh

Ở đây có nghĩa là lấy 3 ký tự tính từ cuối.

Nếu $start là dương còn $length là âm, thì sẽ cắt cả đầu lẫn đuôi. Đầu đánh dấu vị trí nhờ biến $start, còn $length đánh dấu số ký tự bỏ đi tính từ cuối.

echo mb_substr("Nguyễn Đức Anh",6,-3);

// cho kết quả là Đức

Ở ví dụ trên nó sẽ lấy ký tự thứ 6, tức là khoảng trắng, và cắt đi 3 ký tự cuối, do vậy còn mỗi từ ở giữa.

2. Hàm mb_strtolower

Dùng để chuyển tất cả ký tự về dạng viết thường.

Cú pháp của nó như sau:

mb_strtolower(string $string, ?string $encoding = null): string
  • $string là chuỗi đầu vào;
  • Còn $encoding là tham số chỉ kiểu mã hóa của ký tự, thường thì cũng như trên chúng ta để là ‘UTF-8’. Nếu tham số này không được chỉ định thì mã hóa bên trong ký tự sẽ được dùng;

Ví dụ:

echo mb_strtolower("NGUYỄN Đức ANh", 'UTF-8');

// kết quả: nguyễn đức anh

Tôi hay dùng hàm này khi phải xử lý phức tạp về chuỗi, chuyển nó thống nhất về ký tự thường sẽ giúp mã đơn giản hơn, sau khi đạt được kết quả cuối cùng sẽ chuyển về dạng tiêu chuẩn. Ví dụ như trường hợp xử lý họ tên.

3. Hàm mb_strtoupper

Ngược lại với hàm trên, nó dùng để chuyển tất cả ký tự về dạng viết HOA.

Cú pháp của nó như sau:

mb_strtoupper(string $string, ?string $encoding = null): string

Các giải thích thì cũng tương tự như mục 2.

Ví dụ:

echo mb_strtoupper("nguyễn đức anh", 'UTF-8');
// kết quả: NGUYỄN ĐỨC ANH

Hàm này có lẽ ít dùng trong thực tế, vì kiểu văn bản toàn hoa rất khó chịu.

4. Hàm mb_convert_case

Cũng liên quan đến việc chuyển đổi chữ hoa, chữ thường với rất nhiều tùy chọn.

Cú pháp của nó như sau:

mb_convert_case(string $string, int $mode, ?string $encoding = null): string

Trong đó cái $mode chỉ đến kiểu chuyển văn bản mà chúng ta muốn và là tham số bắt buộc phải có.

Ví dụ:

echo mb_convert_case("nguyễn đức anh", MB_CASE_TITLE, "UTF-8");
// kết quả: Nguyễn Đức Anh

echo mb_convert_case("ngUyễn đức aNh", MB_CASE_TITLE, "UTF-8");
// kết quả: Nguyễn Đức Anh

Với mode MB_CASE_TITLE bạn sẽ chuyển chuỗi về dạng viết hoa đầu từ.

Các mode khác bao gồm:

MB_CASE_FOLD, MB_CASE_UPPER_SIMPLE, MB_CASE_LOWER_SIMPLE, và MB_CASE_FOLD_SIMPLE

5. Hàm mb_strlen

Dùng để đếm số lượng ký tự của một chuỗi.

Cú pháp:

mb_strlen(string $string, ?string $encoding = null): int

Ví dụ:

echo mb_strlen("Nguyễn Đức Anh", 'UTF-8');
// Kết quả: 14

Bạn chú ý là các khoảng trống giữa ký tự cũng được tính, do vậy nếu từ dư khoảng trắng, số lượng ký tự sẽ tăng thêm so với thực tế.

Nếu bạn muốn chuỗi có khoảng trắng đúng chuẩn (tức là mỗi từ chỉ cách nhau một khoảng trắng), bạn có thể dùng lệnh sau để khử khoảng trắng dư:

$str2 = preg_replace('/\s+/', ' ', $str);

// Lúc này $str2 sẽ có số lượng khoảng trắng chuẩn  

6. Hàm mb_str_split

Dùng để lấy mảng (array) các ký tự của một chuỗi.

Cú pháp của nó như sau:

mb_str_split(string $string, int $length = 1, ?string $encoding = null): array

Ví dụ:

print_r (mb_str_split("Nguyễn Đức Anh"));

Sẽ cho kết quả là một mảng gồm 14 phần tử:

Array ( [0] => N [1] => g [2] => u [3] => y [4] => ễ [5] => n [6] => [7] => Đ [8] => ứ [9] => c [10] => [11] => A [12] => n [13] => h )

Mỗi phần tử là một ký tự trong chuỗi, bao gồm cả phần tử chỉ khoảng cách.

Ở đây bạn có thể thấy nếu $length không được chỉ định thì giá trị mặc định là 1. Còn nếu không nó sẽ cắt chuỗi theo giá trị của $length. Ví dụ:

print_r (mb_str_split("Nguyễn Đức Anh",3));

Thì kết quả sẽ là:

Array ( [0] => Ngu [1] => yễn [2] => Đứ [3] => c A [4] => nh )

Phần tử ở vị trí số 2 và 3 dù bề ngoài có 2 ký tự nhưng thực ra là 3, vì nó bao gồm cả khoảng trắng nữa. Phần tử cuối cùng thì đúng có 2 ký tự. Vì 14/3 thì kiểu gì cũng có nhóm thiếu 1.

Một lệnh preg cũng dùng để cắt chuỗi ra từng ký tự mà tôi thấy cũng rất tốt là:

preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY);

7. Hàm mb_strpos

Dùng để tìm vị trí xuất hiện đầu tiên của một chuỗi trong chuỗi kia.

Cú pháp:

mb_strpos(
    string $haystack,
    string $needle,
    int $offset = 0,
    ?string $encoding = null
): int|false
  • $offset$encoding không cần thiết lập gì cũng không sao;
  • $haystack là chuỗi cần tìm kiếm;
  • $needle là mẫu tìm kiếm;
  • Vị trí 0 được tính từ đầu chuỗi $haystack;
  • Câu lệnh có phân biệt chữa HOA, chữ thường;
  • Nếu không tìm được, kết quả trả về là FALSE;

Ví dụ ở đây là tìm vị trí xuất hiện của chuỗi mẫu “Đức” trong chuỗi “Nguyễn Đức Anh”:

echo mb_strpos("Nguyễn Đức Anh","Đức");
// Kết quả là 7

Dĩ nhiên $needle hoàn toàn có thể là 1 ký tự, ví dụ:

echo mb_strpos("Nguyễn Đức Anh","ễ");
// Kết quả là 4

Nếu mẫu tìm kiếm xuất hiện nhiều lần trong chuỗi, thì chỉ vị trí đầu tiên được trả về, ví dụ:

echo mb_strpos("Nguyễn Đức Anh","n");
// Kết quả là 5

Chuỗi gốc cần tìm mẫu có 3 ký tự n, nhưng chữ đầu tiên là viết hoa nên so sánh với mẫu là không khớp (câu lệnh có phân biệt chữ hoa, chữ thường). 2 chữ n còn lại phù hợp với mẫu. Chữ n đầu tiên ở vị trí số 5 là kết quả được trả về.

Ngược lại với hàm mb_strpos là hàm mb_strrpos, nó sẽ trả về vị trí cuối cùng của mẫu trong chuỗi. Cú pháp cũng tương tự.

Chẳng hạn với ví dụ về ký tự n kể trên nó sẽ ra kết quả là 12:

echo mb_strrpos("nguyễn đức anh", "n");
// Kết quả là 12

Nếu mẫu tìm kiếm chỉ xuất hiện duy nhất một lần trong chuỗi thì “tình đầu cũng là tình cuối”, do vậy mb_strposmb_strrpos trả về cùng một kết quả.

mb_strrpos cũng phân biệt chữ HOA, chữ thường.

Lưu ý với cả 2 hàm này là nếu ký tự đầu tiên nó sẽ trả về bị trí 0, còn nếu không tìm thấy nó trả về FALSE. Nếu nếu dùng hàm if làm câu lệnh điều kiện chúng ta sẽ phải chỉ rõ nó ==FALSE hay ==0, nếu chỉ quẳng kết quả vào ngoặc tròn với biến đại diện thì 0 và FALSE sẽ bị xem là tương đương nhau. Ví dụ:

$n = mb_strpos("nguyễn đức anh", "n");

if ($n) {echo "có ký tự n";} else {echo "không có ký tự n";}

// Sẽ ra kết quả là không có, đây là kết quả sai

Muốn sửa chúng ta chỉ cần chỉ rõ điều kiện chính xác của biến $n:

if ($n>=0) {echo "có ký tự n";} else {echo "không có ký tự n";}

Phần một về chuỗi tạm dừng ở đây, hy vọng sớm gặp lại các bạn trong bài viết khác.