30/09/2018, 16:19

Cách đếm các kí tự tiếng việt

HIện tai em đang cần đếm các kí tự tiếng việt trong đoạn văn bản. Nhưng không biết làm sao để đọc các dữ liệu có dấu.
input: “dạy nhau học”
output: chỉ cần đếm kí tự như chuỗi “day nhau hoc”

Nguyễn Minh Dũng viết 18:26 ngày 30/09/2018

Cái này cần kiến thức về unicode. Giả sử ta đang đọc file có dấu sử dụng unicode. Sau đó em xem link này để làm.

stackoverflow.com
paxdiablo

How to count characters in a unicode string in C

c, string, unicode, ascii
answered by paxdiablo on 08:45AM - 04 Sep 11

Đạt không có nhiều thời gian nên đành viết vài dòng ngắn gọn thế này, bạn nào có kiến thức về unicode giúp tiếp nhé.

Quân viết 18:29 ngày 30/09/2018

Cách tốt nhất là thay toàn bộ có dấu về không dấu

Minh Hoàng viết 18:27 ngày 30/09/2018

thay như thế nào nhỉ? mình cũng cần phải đọc kí tự tiếng việt đó mà

Quân viết 18:19 ngày 30/09/2018

Ah quên mất, mình có làm trên java không biết C có đuợc không nữa.

Nguyễn Minh Dũng viết 18:23 ngày 30/09/2018

@Rok_Hoang Ví dụ chuỗi “Dạy Nhau Học” thì có độ dài bao nhiêu byte? Hôm trước Đạt bận quá chưa có thời gian nói về cái này.


Vấn đề này là vấn đề khó trong C, có thể java đã có thư viện giải quyết sẵn? Bởi vì Unicode hay nói chính xác hơn là UTF-8 có quy tắc riêng để định nghĩa số lượng byte cho một ký tự Unicode.

Trước hết nói về lý do lịch sử, khi bảng ký tự ASCII ra đời thì các ký là ký tự tiếng Anh. Khi đó chỉ cần 1 byte, 255 ký tự, là có thể định nghĩa đầy đủ bảng ký tự.

Về sau, khi người ta cần thể hiện các ký tự của nhiều ngôn ngữ khác nhau thì họ mới dùng 2 bytes, 65534 ký tự. Rồi vấn đề lại phát sinh khi ta muốn thể hiện tiếng Trung Quốc, Nhật Bản, Hàn Quốc và nhiều loại ngôn ngữ khác nhau thì 2 bytes cũng không đủ.

Nếu chỉ là 2 bytes không đủ, cứ dùng 4 bytes sẽ đủ, 4294967295 ký tự. Nhưng bây giờ lại phát sinh một vấn đề khác, nếu sử dụng 4 bytes cho tất cả các ký tự. Thì khi viết một văn bản tiếng Anh có 10 ký tự, ta phải dùng 40 bytes thay vì 10 bytes như ban đầu.

Và từ đây UTF-8, bản mã tối ưu nhất, đã ra đời. Cách hoạt động của UTF-8 như sau:

Đối với ký tự có

  • 1 byte, thì bit đầu tiên sẽ là 0
  • 2 bytes, thì các bit dầu tiên sẽ là 110, byte tiếp theo 10
  • 3 bytes, thì các bit dầu tiên sẽ là 1110, các byte tiếp theo 10 và 10
  • 4 bytes, thì các bit dầu tiên sẽ là 11110, các byte tiếp theo 10 và 10 và 10

Tham khảo: http://www.wikiwand.com/en/UTF-8#/Description

Khi hiểu được quy tắc của nó, ta có thể đọc một byte lên, kiểm tra các bit đầu để biết được nó là một ký tự có bao nhiêu byte. Từ đó có thể gom lại các bytes đó.

Đây là code ví dụ cách đọc và ghi Utf-8

void write_utf8(unsigned code_point)
{
  if (code_point < 0x80) {
    putchar(code_point);
  } else if (code_point <= 0x7FF) {
    putchar((code_point >> 6) + 0xC0);
    putchar((code_point & 0x3F) + 0x80);
  } else if (code_point <= 0xFFFF) {
    putchar((code_point >> 12) + 0xE0);
    putchar(((code_point >> 6) & 0x3F) + 0x80);
    putchar((code_point & 0x3F) + 0x80);
  } else if (code_point <= 0x10FFFF) {
    putchar((code_point >> 18) + 0xF0);
    putchar(((code_point >> 12) & 0x3F) + 0x80);
    putchar(((code_point >> 6) & 0x3F) + 0x80);
    putchar((code_point & 0x3F) + 0x80);
  } else {
    error("invalid code_point");
  }
}
 
unsigned read_code_point_from_utf8()
{
  int code_unit1, code_unit2, code_unit3, code_unit4;
 
  code_unit1 = getchar();
  if (code_unit1 < 0x80) {
    return code_unit1;
  } else if (code_unit1 < 0xC2) {
    /* continuation or overlong 2-byte sequence */
    goto ERROR1;
  } else if (code_unit1 < 0xE0) {
    /* 2-byte sequence */
    code_unit2 = getchar();
    if ((code_unit2 & 0xC0) != 0x80) goto ERROR2;
    return (code_unit1 << 6) + code_unit2 - 0x3080;
  } else if (code_unit1 < 0xF0) {
    /* 3-byte sequence */
    code_unit2 = getchar();
    if ((code_unit2 & 0xC0) != 0x80) goto ERROR2;
    if (code_unit1 == 0xE0 && code_unit2 < 0xA0) goto ERROR2; /* overlong */
    code_unit3 = getchar();
    if ((code_unit3 & 0xC0) != 0x80) goto ERROR3;
    return (code_unit1 << 12) + (code_unit2 << 6) + code_unit3 - 0xE2080;
  } else if (code_unit1 < 0xF5) {
    /* 4-byte sequence */
    code_unit2 = getchar();
    if ((code_unit2 & 0xC0) != 0x80) goto ERROR2;
    if (code_unit1 == 0xF0 && code_unit2 < 0x90) goto ERROR2; /* overlong */
    if (code_unit1 == 0xF4 && code_unit2 >= 0x90) goto ERROR2; /* > U+10FFFF */
    code_unit3 = getchar();
    if ((code_unit3 & 0xC0) != 0x80) goto ERROR3;
    code_unit4 = getchar();
    if ((code_unit4 & 0xC0) != 0x80) goto ERROR4;
    return (code_unit1 << 18) + (code_unit2 << 12) + (code_unit3 << 6) + code_unit4 - 0x3C82080;
  } else {
    /* > U+10FFFF */
    goto ERROR1;
  }
 
  ERROR4:
    ungetc(code_unit4, stdin);
  ERROR3:
    ungetc(code_unit3, stdin);
  ERROR2:
    ungetc(code_unit2, stdin);
  ERROR1:
    return code_unit1 + 0xDC00;
}

Tham khảo: http://www.wikiwand.com/en/UTF-8#/Sample_code

Bài liên quan
0