Menu

Golang Rune ve Byte: UTF-8 String'ler

Go'da rune ve byte'ın anlamı, string'lerin UTF-8'i nasıl sakladığı, len'in neden bayt saydığı, range'in rune'ları nasıl çözdüğü, string, []byte ve []rune arasında dönüşüm ve bytes paketiyle çalışmak.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Bir Go string'i bir bayt dizisidir; Go kaynak kodu ve string literal'leri UTF-8'dir. Bir byte bu baytlardan biridir. Bir rune ise UTF-8'in 1 ila 4 baytta sakladığı tek bir Unicode karakteridir (bir kod noktası). Go'daki string karışıklığının çoğu ikisini birbirine karıştırmaktan gelir:

UTF-8'de üç bayttır, bu yüzden "語Go" 5 bayt ama 3 rune'dur. İndeks döngüsü beş bayt görür ve 0, 1 ve 2 numaralı baytlar tek başlarına anlamsızdır. range döngüsü UTF-8'i çözer ve 0, 3 ve 4 indekslerinde üç rune verir: i her zaman bir karakter sayısı değil, bir bayt konumudur.

byte ve rune Takma Addır

AdAynı tipLiteralAnlamı
byteuint8byte('A'), 0x41bir baytlık veri
runeint32'A', 'é', '世'bir Unicode kod noktası

Takma ad oldukları için bir byte bir uint8, bir rune bir int32'dir; takma ad ile temel tipi arasında dönüşüm gerekmez. Tek tırnak bir rune, çift tırnak bir string oluşturur. 'ab' bir derleme hatasıdır, çünkü bir rune literal'i tam olarak bir karakter tutar.

Rune'lar sayıdır, bu yüzden üzerlerinde aritmetik yapabilirsiniz:

'7' - '0', bir rakam karakterini değerine çevirmenin klasik yoludur. unicode paketi rune'ları sınıflandırır (IsLetter, IsDigit, IsSpace, IsUpper) ve ASCII olmayan harfler için büyük/küçük harfi doğru değiştirir. %c bir rune'u karakter olarak, %U U+4E16 biçiminde, %q tırnaklı bir rune literal'i olarak yazdırır.

UTF-8 Karakterleri Nasıl Saklar

Kod noktalarıBaytÖrnekler
U+0000 ile U+007F arası1ASCII: a, 7, {
U+0080 ile U+07FF arası2é, ß, ж, ع
U+0800 ile U+FFFF arası3, ,
U+10000 ve üstü4emoji, nadir CJK

ASCII metin UTF-8'de aynıdır; bayt tabanlı kodun testte çoğu zaman çalışıp ilk aksanlı adda bozulmasının nedeni budur. unicode/utf8 paketi doğrudan kodlamayla çalışır:

% x (boşlukla) baytları boşluklarla ayrılmış onaltılık olarak yazdırır. utf8.ValidString bir string'in geçerli UTF-8 olup olmadığını bildirir. Go string'leri yalnızca geçerli UTF-8 değil, herhangi bir bayt tutabilir; range geçersiz bir baytla karşılaştığında utf8.RuneError (U+FFFD, yedek karakter) verir ve bir bayt ilerler.

string, []byte ve []rune Arasında Dönüşüm

DönüşümSonuçMaliyet
[]byte(s)UTF-8 baytlarıkopyalar
[]rune(s)çözülmüş kod noktalarıçözer ve kopyalar (rune başına 4 bayt)
string(b)baytlardan bir stringkopyalar
r bir []rune iken string(r)UTF-8'e kodlarkopyalar
r bir rune iken string(r)tek karakterli bir stringküçük

Baytlara göre ters çevirmek 世界'yi geçersiz UTF-8'e karıştırırdı; reverse'ün rune'lar üzerinde çalışmasının nedeni budur. Rune'lar bile hikâyenin tamamı değildir: é gibi bir karakter e artı birleşen bir aksan olarak da yazılabilir, bu da iki rune'dur. Kullanıcıya görünen karakterler (grapheme cluster'lar) için github.com/rivo/uniseg gibi bir kütüphane kullanın.

Her dönüşüm kopyalar, çünkü string'ler değiştirilemez, slice'lar değiştirilebilirdir. Sık çalışan kodda ileri geri dönüştürmekten kaçının; derleyici bazı durumları (map anahtarı ya da bir karşılaştırmada kullanılan string(b) gibi) kopyayı atlayacak şekilde optimize eder.

İndeksleme Bir Bayt Verir

s[i] bir byte döndürür ve s[i:j] bayt konumlarına göre dilimler:

s := "café"
fmt.Println(s[3])            // 195: the first byte of é
fmt.Println(string(s[3]))    // "Ã": that byte read as a code point
fmt.Println(s[:3])           // "caf"
fmt.Println(s[:4])           // "caf\xc3": half of é, invalid UTF-8

string(s[3]) bir tuzaktır: tek bir baytı string'e dönüştürmek onu baytın kendisi olarak değil, kod noktası 195 olan à olarak ele alır. Karakter sınırlarını bulmak için range'i, strings.Index ailesini (her zaman sınırlarda olan bayt konumları döndürürler) ya da utf8.DecodeRuneInString'i kullanın.

bytes Paketi

bytes, []byte için strings'in aynısıdır: bytes.Contains, bytes.Split, bytes.Fields, bytes.TrimSpace, bytes.Equal, bytes.ToUpper ve diğerleri. Veri bayt olarak geldiğinde (dosya içerikleri, HTTP gövdeleri, ağ buffer'ları) onu kullanın, böylece string'e çevirip geri dönüştürmezsiniz:

bytes.Buffer, io.Reader ve io.Writer'ı gerçekleştiren büyüyebilen bir bayt buffer'ıdır. Baytları hem yazıp hem okuduğunuzda doğru araçtır; bir string oluşturmak için strings.Builder biraz daha ucuzdur. == slice'larda çalışmadığı için byte slice'larını bytes.Equal ile karşılaştırın.

Aralarında Seçim Yapmak

  • Gösterdiğiniz, karşılaştırdığınız ya da aradığınız metin: onu bir string olarak tutun ve karakter karakter dolaşırken range kullanın.
  • Karakter konumları, ters çevirme, n karaktere kırpma: []rune'a dönüştürün.
  • G/Ç, hash'leme, kodlama, ikili protokoller: []byte ve bytes paketini kullanın.
  • Tek bir karakter: bir rune. Tek bir ham bayt: bir byte.

Sıkça Sorulan Sorular

Go'da rune nedir?

rune, int32 için bir takma addır ve bir Unicode kod noktasını temsil eder. Bir rune literal'i tek tırnakla yazılır: 'a' 97, 'é' 233, '世' 19990'dır. Bir string üzerinde for i, r := range s ile dönmek, string'in UTF-8 baytlarından çözülmüş rune'lar verir.

Go'da rune ile byte arasındaki fark nedir?

Bir byte (uint8 için takma ad) 8 bitlik ham veridir. Bir rune (int32 için takma ad) bütün bir Unicode karakteridir. Bir UTF-8 string'inde ASCII karakterler birer bayt tutar, diğer karakterler iki ila dört bayt tutar ama yine de tek bir rune'dur. len(s) baytları, utf8.RuneCountInString(s) rune'ları sayar.

Go'da bir string'in karakterleri üzerinde nasıl dönülür?

for i, r := range s kullanın. Her yineleme bayt konumu i'yi ve rune r'yi verir, bu yüzden çok baytlı karakterler doğru ele alınır. Düz bir indeks döngüsü for i := 0; i < len(s); i++ baytları ziyaret eder ve ASCII olmayan karakterleri parçalara böler.

Go'da bir string nasıl byte slice'ına dönüştürülür?

b := []byte(s), string'in baytlarını yeni bir slice'a kopyalar. string(b) yine bir kopyayla geri dönüştürür. Karakterlerle çalışmanız gerektiğinde, örneğin bir string'i ters çevirmek ya da ilk n karakterini almak için, bunun yerine []rune(s) kullanın.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA