unicode va utf8 paketlari
Go tilida satrlar (string) ichida UTF-8 kodlashda saqlanadi. Bu esa qiziq bir holatga olib keladi: ba'zi belgilar (masalan, lotin harflari) 1 bayt egallasa, boshqalari (masalan, emoji yoki ba'zi maxsus belgilar) 2, 3 yoki 4 baytgacha joy egallashi mumkin.
Shuning uchun satrning bayt uzunligi (len(s)) har doim ham uning haqiqiy belgilar soniga teng bo'lavermaydi. Aynan shu farqni to'g'ri boshqarish uchun unicode/utf8 (kodlash bilan ishlash) va unicode (belgi turlarini aniqlash) paketlari kerak bo'ladi.
import (
"unicode"
"unicode/utf8"
)
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
// ʻ — o'ng qo'shtirnoq belgisi (U+02BB), UTF-8'da 2 bayt egallaydi
s := "gʻalati"
fmt.Println("Bayt uzunligi:", len(s))
fmt.Println("Belgilar soni:", utf8.RuneCountInString(s))
emoji := "Salom 😊"
fmt.Println("Bayt uzunligi:", len(emoji))
fmt.Println("Belgilar soni:", utf8.RuneCountInString(emoji))
}
Natija:
Bayt uzunligi: 8
Belgilar soni: 7
Bayt uzunligi: 10
Belgilar soni: 7
[!IMPORTANT]
gʻalatiso'zida 7 ta belgi bor, lekinʻbelgisi 2 bayt egallagani uchunlen()funksiyasi8ni qaytaradi. Agar siz Uzbek tilidagi matnlar (o',g'kabi maxsus belgili so'zlar) yoki emoji bilan ishlasangiz, hech qachonlen(s)ni "belgilar soni" sifatida ishlatmang — buning o'rnigautf8.RuneCountInString(s)dan foydalaning.
for rangeGoda for i, r := range s orqali satr bo'ylab aylanganda, i — belgining bayt indeksi (ketma-ket 0,1,2,... emas!), r esa haqiqiy belgi (rune turida, ya'ni Unicode kod nuqtasi):
package main
import "fmt"
func main() {
for i, r := range "Go!" {
fmt.Println(i, r, string(r))
}
}
Natija:
0 71 G
1 111 o
2 33 !
Bu yerda har bir belgi 1 baytli bo'lgani uchun indekslar ketma-ket (0, 1, 2) chiqdi. Agar satrda ko'p baytli belgilar bo'lganida, indekslar orasida "sakrashlar" bo'lar edi — chunki Go har safar keyingi TO'LIQ belgigacha o'tadi, keyingi baytga emas.
rune) massiviga aylantirishSatrni indeks orqali to'g'ridan-to'g'ri kesish (masalan, s[0:3]) bayt darajasida ishlaydi va ko'p baytli belgilarni "sindirib" qo'yishi mumkin. Xavfsiz ishlash uchun avval satrni []rune turiga aylantirish tavsiya etiladi:
package main
import "fmt"
func main() {
runes := []rune("Salom")
fmt.Println(runes) // har bir belgining sonli (Unicode) qiymati
fmt.Println(string(runes)) // orqaga satrga aylantiramiz
fmt.Println(len(runes)) // endi bu HAQIQIY belgilar soni
}
Natija:
[83 97 108 111 109]
Salom
5
[]rune massiviga aylantirilgandan so'ng, len() endi to'g'ri ishlaydi, chunki har bir element aynan bitta belgini ifodalaydi (bayt emas).
unicode.Is...()unicode paketi bitta belgi (rune) qanday turga tegishli ekanligini (harf, raqam, bo'sh joy va h.k.) tekshirish uchun funksiyalar taqdim etadi:
package main
import (
"fmt"
"unicode"
)
func main() {
fmt.Println(unicode.IsLetter('A')) // harfmi?
fmt.Println(unicode.IsDigit('9')) // raqammi?
fmt.Println(unicode.IsSpace(' ')) // bo'sh joymi?
fmt.Println(unicode.IsUpper('A')) // katta harfmi?
fmt.Println(unicode.IsLower('a')) // kichik harfmi?
fmt.Println(unicode.IsPunct('!')) // tinish belgisimi?
}
Natija:
true
true
true
true
true
true
Bu funksiyalar ko'pincha foydalanuvchi kiritgan matnni tekshirishda (masalan, parolda kamida bitta raqam borligini tekshirish) ishlatiladi.
ToUpper() va ToLower()strings.ToUpper()/ToLower() butun satr bilan ishlasa, unicode.ToUpper()/ToLower() xuddi shu ishni bitta rune (belgi) darajasida bajaradi:
package main
import (
"fmt"
"unicode"
)
func main() {
fmt.Println(string(unicode.ToUpper('a')))
fmt.Println(string(unicode.ToLower('A')))
}
Natija:
A
a
utf8.ValidString()Tashqi manbadan (masalan, tarmoqdan yoki fayldan) kelgan ma'lumot har doim ham to'g'ri UTF-8 formatida bo'lavermaydi. Buni tekshirish uchun:
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
fmt.Println(utf8.ValidString("Go 学习")) // to'g'ri UTF-8 satrmi?
}
Natija:
true
| Vazifa | Funksiya |
|---|---|
| Haqiqiy belgilar sonini bilish | utf8.RuneCountInString(s) |
| Satrni belgi-belgi qayta ishlash | for i, r := range s yoki []rune(s) |
| Belgi harfmi, raqammi, bo'sh joymi | unicode.IsLetter(), IsDigit(), IsSpace() |
| Bitta belgini katta/kichik qilish | unicode.ToUpper() / ToLower() |
| Satr to'g'ri UTF-8 ekanligini tekshirish | utf8.ValidString() |
[!NOTE] Qoida sifatida yodda tuting:
len(s)— baytlar soni,utf8.RuneCountInString(s)— belgilar soni. Faqat ingliz alifbosidagi matnlar bilan ishlaganda ikkalasi bir xil chiqadi, lekin o'zbekcha maxsus belgilar (o',g'), kirillcha yoki emoji bilan ishlaganda bu farq muhim ahamiyat kasb etadi.