Menu

Rune dan Byte di Golang: Penjelasan String UTF-8

Arti rune dan byte di Go, cara string menyimpan UTF-8, kenapa len menghitung byte, cara range men-decode rune, konversi antara string, []byte, dan []rune, serta bekerja dengan package bytes.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

String di Go adalah rangkaian byte, dan source code serta literal string Go memakai UTF-8. byte adalah salah satu byte itu. rune adalah satu karakter Unicode (sebuah code point), yang disimpan UTF-8 dalam 1 sampai 4 byte. Sebagian besar kebingungan soal string di Go berasal dari tertukarnya keduanya:

語 berukuran tiga byte di UTF-8, jadi "語Go" berukuran 5 byte tapi berisi 3 rune. Loop indeks melihat lima byte, dan byte 0, 1, dan 2 tidak bermakna kalau berdiri sendiri. Loop range men-decode UTF-8 dan menghasilkan tiga rune di indeks 0, 3, dan 4: i selalu merupakan offset byte, bukan jumlah karakter.

byte dan rune adalah alias

NamaTipe yang sama denganLiteralArti
byteuint8byte('A'), 0x41satu byte data
runeint32'A', 'é', '世'satu code point Unicode

Karena keduanya alias, byte adalah uint8 dan rune adalah int32; tidak perlu konversi antara alias dan tipe dasarnya. Tanda kutip tunggal menghasilkan rune, tanda kutip ganda menghasilkan string. 'ab' adalah compile error, karena literal rune berisi tepat satu karakter.

Rune adalah angka, jadi kamu bisa melakukan aritmetika padanya:

'7' - '0' adalah cara klasik untuk mengubah karakter digit menjadi nilainya. Package unicode mengklasifikasikan rune (IsLetter, IsDigit, IsSpace, IsUpper) dan mengubah huruf besar dan kecil dengan benar untuk huruf non-ASCII. %c mencetak rune sebagai karakter, %U dalam bentuk U+4E16, %q sebagai literal rune bertanda kutip.

Cara UTF-8 menyimpan karakter

Code pointByteContoh
U+0000 sampai U+007F1ASCII: a, 7, {
U+0080 sampai U+07FF2é, ß, ж, ع
U+0800 sampai U+FFFF3語, €, 한
U+10000 ke atas4emoji, CJK yang langka

Teks ASCII sama persis di UTF-8, itulah sebabnya kode berbasis byte sering berjalan lancar saat diuji lalu rusak pada nama pertama yang memakai aksen. Konverter teks ke biner menampilkan byte UTF-8 dari teks apa pun yang kamu tempel. Package unicode/utf8 bekerja langsung dengan encoding-nya:

% x (dengan spasi) mencetak byte dalam heksadesimal yang dipisahkan spasi. utf8.ValidString melaporkan apakah sebuah string berisi UTF-8 yang valid. String Go boleh berisi byte apa pun, tidak hanya UTF-8 yang valid; saat range bertemu byte yang tidak valid, ia menghasilkan utf8.RuneError (U+FFFD, karakter pengganti) lalu maju satu byte.

Konversi antara string, []byte, dan []rune

KonversiHasilBiaya
[]byte(s)byte UTF-8-nyamenyalin
[]rune(s)code point hasil decodemen-decode dan menyalin (4 byte per rune)
string(b)string dari bytemenyalin
string(r) dengan r berupa []runemeng-encode ke UTF-8menyalin
string(r) dengan r berupa runestring berisi satu karakterkecil

Membalik berdasarkan byte akan mengacak 世界 menjadi UTF-8 yang tidak valid, itulah sebabnya reverse bekerja pada rune. Bahkan rune pun belum menceritakan semuanya: karakter seperti é juga bisa ditulis sebagai e ditambah aksen kombinasi, yaitu dua rune. Untuk karakter yang terlihat oleh pengguna (grapheme cluster), pakai library seperti github.com/rivo/uniseg.

Setiap konversi melakukan penyalinan, karena string bersifat immutable sedangkan slice tidak. Di kode yang sering dieksekusi, hindari konversi bolak-balik; compiler mengoptimalkan beberapa kasus (seperti string(b) yang dipakai sebagai key map atau dalam perbandingan) untuk melewati penyalinan.

Indeks menghasilkan byte

s[i] mengembalikan byte, dan s[i:j] memotong berdasarkan offset byte:

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]) adalah jebakan: mengubah satu byte menjadi string memperlakukannya sebagai code point 195, yaitu Ã, bukan byte itu sendiri. Untuk menemukan batas karakter, pakai range, keluarga strings.Index (yang mengembalikan offset byte yang selalu tepat di batas karakter), atau utf8.DecodeRuneInString.

Package bytes

bytes adalah cerminan strings untuk []byte: bytes.Contains, bytes.Split, bytes.Fields, bytes.TrimSpace, bytes.Equal, bytes.ToUpper, dan seterusnya. Pakai package ini saat data datang dalam bentuk byte (isi file, body HTTP, buffer jaringan), supaya kamu tidak perlu mengubahnya menjadi string lalu kembali lagi:

bytes.Buffer adalah buffer byte yang bisa membesar dan mengimplementasikan io.Reader serta io.Writer. Ini alat yang tepat saat kamu menulis sekaligus membaca byte; untuk menyusun string, strings.Builder sedikit lebih murah. Bandingkan byte slice dengan bytes.Equal, karena == tidak bisa dipakai pada slice.

Memilih di antara keduanya

  • Teks yang kamu tampilkan, bandingkan, atau cari: biarkan sebagai string, dan pakai range saat menelusurinya karakter demi karakter.
  • Posisi karakter, membalik, memotong menjadi n karakter: ubah menjadi []rune.
  • I/O, hashing, encoding, protokol biner: pakai []byte dan package bytes.
  • Satu karakter: rune. Satu byte mentah: byte.

Pertanyaan yang sering diajukan

Apa itu rune di Go?

rune adalah alias untuk int32 dan mewakili satu code point Unicode. Literal rune ditulis dengan tanda kutip tunggal: 'a' bernilai 97, 'é' bernilai 233, '世' bernilai 19990. Melakukan range pada string dengan for i, r := range s memberimu rune, hasil decode dari byte UTF-8 string itu.

Apa perbedaan rune dan byte di Go?

byte (alias untuk uint8) adalah 8 bit data mentah. rune (alias untuk int32) adalah satu karakter Unicode utuh. Di string UTF-8, karakter ASCII masing-masing memakai satu byte, sedangkan karakter lain memakai dua sampai empat byte tapi tetap satu rune. len(s) menghitung byte; utf8.RuneCountInString(s) menghitung rune.

Bagaimana cara melakukan perulangan pada karakter sebuah string di Go?

Pakai for i, r := range s. Setiap iterasi memberikan offset byte i dan rune r, jadi karakter multi-byte ditangani dengan benar. Loop indeks biasa for i := 0; i < len(s); i++ mengunjungi byte, yang memotong karakter non-ASCII menjadi kepingan.

Bagaimana cara mengubah string menjadi byte slice di Go?

b := []byte(s) menyalin byte string itu ke slice baru. string(b) mengubahnya kembali, juga dengan menyalin. Pakai []rune(s) sebagai gantinya saat kamu perlu bekerja dengan karakter, misalnya untuk membalik string atau mengambil n karakter pertamanya.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai