​UTF-8: Boshidan-oxirigacha! 2-qism! utf8_strlen!

Agar UTF-8 haqida qisqacha ma'lumot olmoqchi bo'lsangiz, 1-qismga o'ting.

Agar 1-maqolani o'qigan bo'lsangiz, UTF-8 da belgilar 1 baytdan 4 baytgacha bo'lishi mumkin deb o'tganman. Agar shunday bo'lsa, "AЩぁ𐄳" qator (string) uzunligi nechchi bo'lishi kerak?

#include <iostream>
#include <locale>
#include <string>


int main()
{
    std::string str{"AЩぁ𐄳"};
    
    std::cout<<"LENGTH = "<<str.length()<<std::endl;
    return 0;
}

Dastur natijasi:

LENGTH = 10

Bizga esa 4 kerak.

Keling oldin UNICODE dagi belgi UTF-8 ga qanday tartibda o'tkazilishini o'rgnaib chiqsak. U 3 da qadamdan iborat.

1-qadam: UNICODE dagi belgilarni saqlashga kerak bo'ladigan BAYT lar sonini aniqlash, quyidagi jadval asosida bo'ladi.

BELGILAR ORALIG'I (UNICODE)KERAK BO'LADIGAN BAYTLAR SONI
00000000-0000007F1
00000080-000007FF2
00000800-0000FFFF3
00010000-0010FFFF4

Ya'ni, agar biz UNICODE dagi U+0080 belgini UTF-8 da saqlamoqchi bo'lsak, bizga 2 bayt kerak bo'ladi.

2-qadam: Kerak bo'lgan baytlar sonidan kelib chiqib, quyidagi jadval asosida eng birinchi turgan baytning bit qiymatlarini o'zgartirish kerak.

0xxxxxxxagar 1 bayt bo'lsa
110xxxxxagar 2 bayt bo'lsa
1110xxxxagar 3 bayt bo'lsa
11110xxxagar 4 bayt bo'lsa

1 tadan ko'p bo'lgan holatda, keyingi baytlarning boshida har doim 10 (ikkilikda) bo'lishi lozim. Umuman olganda, baytlar sonidan kelib chiqib quyidagi jadvalni shablon sifatida olsak bo'ladi.

Baytlar soniKerakli bitlarShablon
170xxxxxxx
211110xxxxx 10xxxxxx
3161110xxxx 10xxxxxx 10xxxxxx
42111110xxx 10xxxxxx 10xxxxxx 10xxxxxx

xxxx - bular UNICODE dagi qiymatni saqlashga ishlatiladigan joylar (bit ko'rinishida).

3-qadam: UNICODE dagi birorta belgini olib, uning qiymatidan kelib chiqib keraklicha bayt uzunlikni tanlash kerak va xxxx larning o'rniga UNICODE dagi belgi qiymatini joylashtirish kerak. Ortib qolgan joylar esa 0 bilan to'ldiriladi.

Yuqoridagi 3-da qadam bu tarjima (wikipediadan). Endi keling, misol tariqasida ketma-ket tushuntirsam. Sal murakkab bo'lsada, bir vaqtning o'zida 4 ta belgi bilan ishlasak, manimcha tushinish oson bo'ladi.

Belgilar (UNICODE da):

IZOH\BELGIAЩ𐄳
UNICODE dagi kodiU+0041U+0429U+3041U+10133
Kerak bo'ladigan baytlar soni1
[00000000-0000007F] oraliqda
2
[00000080-000007FF] oraliqda
3
[00000800-0000FFFF] oraliqda
4
[00010000-0010FFFF] oraliqda
Ikkilik sanoq sistemada ko'rinishi1000001100001010011100000100000110000000100110011

2-qadamdagi shablonlardan foydalanib "x" larga mos uzunlikka ajratsak, yuqoridagi ikkilikdagi qiymatlarini:

0xxxxxxx
1000001
110xxxxx 10xxxxxx
10000   101001
1110xxxx 10xxxxxx 10xxxxxx
11   000001    00000
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
10000   000100   110011


IZOH\BELGIAЩ𐄳
Yuqoridagini mox ravizda x lar o'rniga qiymatlarni joylashtiramiz, yetmay qolganiga 0 qo'yamiz0100000111010000 1010100111100011 10000001 1000000111110000 10010000 10000100 10110011
Endi shu 2 likdagi qiymatlarni 16 likda yozamiz.0x410xD0A90xE381810xF09084B3

UTF-8 dagi natijalar esa quyidagicha:

A - U+0041 = 0x41
Щ - U+0429 = 0xD0A9
ぁ - U+3041 = 0xE38181
𐄳 - U+10133 = 0xF09084B3

Demak xulosa: Agar baytning boshidagi bitlari mos ravishda:

0 bo'lsa, demak u 1 baytli UTF-8 belgi.

110 bo'lsa, demak 2 baytli belgi

1110 bo'lsa demak, 3 baytli belgi

11110 bo'lsa, demak 4 baytli belgi.

Shu qoidadan kelib chiqib, utf8_strlen funksiyamiz quyidagi ko'rinishda bo'ladi.

#include <iostream>
#include <locale>
#include <string>


int utf8_strlen(const std::string& s) {
    int len = 0;
    int i = 0;
    while(i < s.length()) {
        char c = s.at(i);
        if ((c & 0xF8) == 0xF0) {// 0xF8 = 1111 1000, 0xF0 = 1111 0000
            i += 4;
        } else if ((c & 0xF0) == 0xE0) { //0xE0 = 1110 0000
            i += 3;
        } else if ((c & 0xE0) == 0xC0) { //0xC0 = 1100 0000
            i += 2;
        } else { //if ((c & 0x80) == 0) { //0x80 = 1000 0000
            i++;
        }
        
        len++;
    }
    
    return len;
}


int utf8_strlen2(const std::string& s)
{
    int len = 0;
    for(int i = 0; i < s.length(); i++) {
        char c = s.at(i);
        if ((c & 0xC0) != 0x80) { //0xC0 = 1100 0000, 0x80 = 1000 0000
            len++;
        }
    }
    
    return len;
}


int main()
{
    std::string str{"AЩぁ𐄳"};
    
    std::cout<<"LENGTH = "<<str.length()<<std::endl;
    std::cout<<"UTF8 LENGTH = "<<utf8_strlen(str)<<std::endl;
    std::cout<<"UTF8 LENGTH2 = "<<utf8_strlen2(str)<<std::endl;
    return 0;
}

Natija:

LENGTH = 10
UTF8 LENGTH = 4
UTF8 LENGTH2 = 4
Eslatma: utf8_strlen funksiya utf8_strlen2 ga nisbatan tez ishlaydi, chunki utf8_strlen da birinchi bayt tekshirilib qolganlari shundoq tashlab ketiladi. Ikkinchi funksiyada esa, bayt boshi 10 dan (ikkilikda) boshlaganlarni tekshiriladi. Shuning uchun ikkinchi funksiya 0 dan s.length() gacha to'liq aylanadi.

Manimcha bugunga yetarli.

C++ utf8 unicode 24-Fevral 23:57 501

shranet

Muallif haqida

Ruslan Abdullayev Shonazarovich


Qiziq bo‘ladi:


Birinchi bo‘ling!

Iltimos, fikr bildirish uchun saytga kiring yoki ro‘yxatdan o‘ting!