Apa itu Rune?

188

Apa itu runein Go?

Saya sudah googling tetapi Golang hanya mengatakan dalam satu baris: runeadalah alias untukint32 .

Tapi kenapa bilangan bulat digunakan di sekitar seperti bertukar kasus?

Berikut ini adalah swapcase fungsi. Apa itu semua <=dan -?

Dan mengapa tidak switchpunya argumen?

&&harus berarti dan tetapi apa itu r <= 'z'?

func SwapRune(r rune) rune {
    switch {
    case 'a' <= r && r <= 'z':
        return r - 'a' + 'A'
    case 'A' <= r && r <= 'Z':
        return r - 'A' + 'a'
    default:
        return r
    }
}

Sebagian besar dari mereka berasal dari http://play.golang.org/p/H6wjLZj6lW

func SwapCase(str string) string {
    return strings.Map(SwapRune, str)
}

Saya mengerti ini adalah pemetaan runeuntuk stringsehingga dapat mengembalikan string bertukar. Tetapi saya tidak mengerti bagaimana tepatnya runeatau bytebekerja di sini.

Quentin Gibson
sumber
Sidenote: Ini tidak melakukan apa yang pembaca ingin lakukan untuk kata bahasa Inggris "café" dan lainnya - apalagi bahasa lain. Go memiliki perpustakaan dengan dukungan yang layak untuk varian yang benar-benar bermanfaat dari jenis transformasi ini.
RedGrittyBrick
2
Jika ada yang ingin tahu dari mana kata "rune" berasal: en.wikipedia.org/wiki/Runic_(Unicode_block)
Matt Browne
A []runedapat diatur ke tipe boolean, numerik, atau tipe string. Lihat stackoverflow.com/a/62739051/12817546 .
Tom J

Jawaban:

149

Rune literal hanyalah nilai integer 32-bit ( namun mereka adalah konstanta yang tidak diketik, sehingga tipenya dapat berubah ). Mereka mewakili codepoint unicode. Misalnya, Rune literal 'a'sebenarnya adalah angka 97.

Karenanya program Anda hampir sama dengan:

package main

import "fmt"

func SwapRune(r rune) rune {
    switch {
    case 97 <= r && r <= 122:
        return r - 32
    case 65 <= r && r <= 90:
        return r + 32
    default:
        return r
    }
}

func main() {
    fmt.Println(SwapRune('a'))
}

Seharusnya jelas, jika Anda melihat pemetaan Unicode, yang identik dengan ASCII dalam rentang itu. Lebih jauh, 32 sebenarnya adalah offset antara codepoint huruf besar dan huruf kecil dari karakter. Jadi dengan menambahkan 32untuk 'A', Anda mendapatkan 'a'dan sebaliknya.

topskip
sumber
12
Ini jelas hanya berfungsi untuk karakter ASCII dan tidak untuk karakter beraksen seperti 'ä', apalagi kasus yang lebih rumit seperti 'ı' (U + 0131). Go memiliki fungsi khusus untuk memetakan ke huruf kecil seperti unicode.ToLower(r rune) rune.
topskip
2
Dan untuk menambahkan jawaban yang benar @ topskip dengan fungsi SwapCase yang bekerja untuk semua codepoint dan bukan hanya az:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
ANisus
22
Runes adalah nilai int32. Itulah seluruh jawabannya. Mereka tidak "dipetakan" .
thwd
@AlixAxel: Perilaku SimpleFold pada dasarnya sama (Ini juga menggunakan ToLower dan ToUpper untuk sebagian besar rune). Ada beberapa kasus di mana ia berbeda seperti: DZ-> Dz, Dz-> dz, dz-> DZ. SwapRune saya sebagai gantinya akan pergi: DZ-> dz, Dz-> DZ, dz-> DZ. Saya suka saran Anda lebih baik :)
ANisus
3
Jadi rune mirip dengan karakter C?
Kenny Worden
53

Dari catatan rilis Go lang: http://golang.org/doc/go1#rune

Rune adalah Tipe. Ini menempati 32bit dan dimaksudkan untuk mewakili Unicode CodePoint . Sebagai analogi, karakter bahasa Inggris yang disandikan dalam 'ASCII' memiliki 128 poin kode. Dengan demikian dapat masuk ke dalam byte (8bit). Dari asumsi (keliru) ini, C memperlakukan karakter sebagai 'byte' char, dan 'string' sebagai 'urutan karakter' char*.

Tapi coba tebak. Ada banyak simbol lain yang diciptakan oleh manusia selain simbol 'abcde ..'. Dan ada begitu banyak yang kita butuhkan 32 bit untuk mengkodekannya.

Di golang maka a stringadalah urutan bytes. Namun, karena beberapa byte dapat mewakili titik kode rune, nilai string juga dapat berisi rune. Jadi, itu dapat dikonversi menjadi []rune, atau sebaliknya.

Paket unicode http://golang.org/pkg/unicode/ dapat memberikan rasa kekayaan tantangan.

fabrizioM
sumber
6
Dengan Unicode 6.3 terbaru, ada lebih dari 110.000 simbol yang ditentukan. Ini membutuhkan setidaknya 21-bit representasi dari setiap titik kode, jadi a runeseperti int32dan memiliki banyak bit.
Rick-777
2
Anda mengatakan "a stringadalah urutan runes" - Saya tidak berpikir itu benar? Go blog : "string hanya setumpuk byte"; Go lang spec : "Nilai string adalah urutan byte (mungkin kosong)"
Chris Martin
1
Saya masih bingung, jadi apakah string array rune atau array byte? Apakah bisa dipertukarkan?
gogofan
1
@prvn Itu salah. Ini seperti mengatakan gambar bukan urutan byte, ini urutan piksel. Tapi, sebenarnya, di bawahnya, serangkaian byte. String adalah serangkaian byte, bukan rune. Silakan baca speknya .
Inanc Gumus
1
@prvn Tapi, Anda tidak bisa mengatakannya not bytes. Kemudian, Anda mungkin berkata: "String terdiri dari rune dan rune terdiri dari byte" Sesuatu seperti itu. Kemudian lagi. itu tidak sepenuhnya benar.
Inanc Gumus
28

Saya telah mencoba untuk menjaga bahasa saya tetap sederhana sehingga orang awam mengerti rune.

Rune adalah karakter. Itu dia.

Ini adalah karakter tunggal. Ini adalah karakter dari alfabet apa pun dari bahasa apa pun dari mana saja di dunia.

Untuk mendapatkan string yang kita gunakan

double-quotes ""

ATAU

back-ticks ``

String berbeda dari rune. Dalam rune kita gunakan

single-quotes ''

Sekarang rune juga merupakan alias untuk int32... Eh Apa?

Alasan Rune adalah alias untuk int32karena kita melihat bahwa dengan skema pengkodean seperti di bawah ini masukkan deskripsi gambar di sini

setiap karakter memetakan ke beberapa nomor dan itu nomor yang kita simpan. Sebagai contoh, a peta ke 97 dan ketika kita menyimpan nomor bahwa itu hanya jumlah dan sehingga ini cara Rune adalah alias untuk int32. Tapi bukan sembarang nomor. Ini adalah angka dengan 32 'nol dan satu' atau '4' byte. (Catatan: UTF-8 adalah skema penyandian 4 byte)

Bagaimana rune berhubungan dengan string?

String adalah kumpulan rune. Dalam kode berikut:

    package main

    import (
        "fmt"
    )

    func main() {
        fmt.Println([]byte("Hello"))
    }

Kami mencoba mengonversi string ke aliran byte. Outputnya adalah:

[72 101 108 108 111]

Kita dapat melihat bahwa masing-masing byte yang membentuk string itu adalah sebuah rune.

Suhail Gupta
sumber
2
A string is not a collection of runesini tidak sepenuhnya benar. Sebaliknya, string adalah irisan byte, yang dikodekan dengan utf8. Setiap karakter dalam string sebenarnya membutuhkan 1 ~ 3 byte, sedangkan setiap rune membutuhkan 4 byte. Anda dapat mengonversi antara string dan [] rune, tetapi keduanya berbeda.
Eric Wang
2
Rune bukan karakter, sebuah rune merepresentasikan sebuah codepoint unicode. Dan codepoint tidak selalu menunjuk ke satu karakter.
Inanc Gumus
Layak untuk menambahkan bahwa "sebuah rune juga merupakan alias untuk int32" ya, tapi itu tidak berarti itu berguna untuk kompresi orang miskin ... Jika Anda menekan sesuatu seperti 55296 konversi string tersesat: Go Playground
kubanczyk
27

Saya tidak memiliki reputasi yang cukup untuk mengirim komentar ke jawaban fabrizioM , jadi saya harus mempostingnya di sini.

Jawaban Fabrizio sebagian besar benar, dan dia tentu saja menangkap esensi masalah - meskipun ada perbedaan yang harus dibuat.

Sebuah string TIDAK harus berupa urutan rune. Ini adalah pembungkus lebih dari 'sepotong byte', sepotong menjadi pembungkus atas array Go. Apa bedanya ini?

Sebuah Rune jenis adalah tentu nilai 32-bit, yang berarti urutan nilai dari jenis Rune akan selalu memiliki beberapa jumlah bit x * 32. String, menjadi urutan byte, sebaliknya memiliki panjang x * 8 bit. Jika semua string sebenarnya dalam Unicode, perbedaan ini tidak akan berdampak. Karena string adalah irisan byte , Go dapat menggunakan ASCII atau pengkodean byte sewenang-wenang lainnya.

Namun demikian, string literal harus ditulis ke dalam sumber yang disandikan dalam UTF-8.

Sumber informasi: http://blog.golang.org/strings

Strangework
sumber
1
Poin bagus! Setiap rune membutuhkan 4 byte, tetapi setiap karakter dalam string dikodekan dengan utf8, sehingga hanya 1 ~ 3 byte paling banyak.
Eric Wang
16

(Mendapat perasaan bahwa jawaban di atas masih tidak menyatakan perbedaan & hubungan antara stringdan []runesangat jelas, jadi saya akan mencoba menambahkan jawaban lain dengan contoh.)

Seperti @Strangeworkjawaban yang dikatakan, stringdan []runediam berbeda.

Perbedaan - string& []rune:

  • string valueadalah slice byte read-only. Dan, string literal dikodekan dalam utf-8. Setiap karakter stringsebenarnya membutuhkan 1 ~ 3 byte, sementara masing rune- masing karakter 4 byte
  • Untuk string, keduanya len()dan indeks didasarkan pada byte.
  • Untuk []rune, keduanya len()dan indeks didasarkan pada rune (atau int32).

Hubungan - string& []rune:

  • Ketika Anda mengkonversi dari stringmenjadi []rune, setiap karakter utf-8 dalam string itu menjadi arune .
  • Demikian pula dalam konversi terbalik, saat mengkonversi dari []rune ke string, masing-masing runemenjadi karakter utf-8 di string.

Kiat:

  • Anda dapat mengkonversi antara stringdan []rune, tetapi masih berbeda, dalam kedua jenis & ukuran keseluruhan.

(Saya akan menambahkan contoh untuk menunjukkannya dengan lebih jelas.)


Kode

string_rune_compare.go:

// string & rune compare,
package main

import "fmt"

// string & rune compare,
func stringAndRuneCompare() {
    // string,
    s := "hello你好"

    fmt.Printf("%s, type: %T, len: %d\n", s, s, len(s))
    fmt.Printf("s[%d]: %v, type: %T\n", 0, s[0], s[0])
    li := len(s) - 1 // last index,
    fmt.Printf("s[%d]: %v, type: %T\n\n", li, s[li], s[li])

    // []rune
    rs := []rune(s)
    fmt.Printf("%v, type: %T, len: %d\n", rs, rs, len(rs))
}

func main() {
    stringAndRuneCompare()
}

Menjalankan:

jalankan string_rune_compare.go

Keluaran:

hello你好, type: string, len: 11
s[0]: 104, type: uint8
s[10]: 189, type: uint8

[104 101 108 108 111 20320 22909], type: []int32, len: 7

Penjelasan:

  • String hello你好memiliki panjang 11, karena 5 karakter pertama masing-masing mengambil 1 byte saja, sedangkan 2 karakter Cina terakhir masing-masing membutuhkan 3 byte.

    • Jadi, total bytes = 5 * 1 + 2 * 3 = 11
    • Sejak len() pada string didasarkan pada byte, maka baris pertama dicetaklen: 11
    • Karena indeks pada string juga didasarkan pada byte, maka 2 baris berikut ini mencetak nilai tipe uint8(karena byteini adalah tipe alias uint8, dalam perjalanan).
  • Ketika mengkonversi stringke []rune, ia menemukan 7 utf8 karakter, sehingga 7 rune.

    • Karena len()on []runedidasarkan pada rune, maka baris terakhir dicetaklen: 7 .
    • Jika Anda beroperasi []runemelalui indeks, itu akan mengakses berdasarkan rune.
      Karena setiap rune berasal dari karakter utf8 di string asli, maka Anda juga bisa mengatakan keduanya len()dan operasi indeks []runedidasarkan pada karakter utf8.
Eric Wang
sumber
"Untuk string, baik len () dan index didasarkan pada byte." Bisakah Anda jelaskan sedikit lebih banyak? Ketika saya melakukannya fmt.Println("hello你好"[0])mengembalikan titik kode UTF-8 yang sebenarnya, bukan byte.
Julian
@Julian Silakan lihat output dari program dalam jawabannya, karena s[0], ia mencetak s[0]: 104, type: uint8, tipenya uint8, berarti byte. Untuk karakter ASCII seperti hutf-8 juga menggunakan byte tunggal untuk mewakilinya, sehingga titik kode sama dengan byte tunggal; tetapi untuk karakter Cina suka , itu menggunakan 3 byte.
Eric Wang
Contoh klarifikasi. Saya mengutip Anda di sini stackoverflow.com/a/62739051/12817546 .
Tom J
7

Semua orang telah membahas bagian yang berhubungan dengan rune, jadi saya tidak akan membicarakan hal itu.

Namun, ada juga pertanyaan terkait switchtidak memiliki argumen. Ini hanya karena di Golang, switchtanpa ekspresi adalah cara alternatif untuk mengekspresikan logika if / else. Misalnya, menulis ini:

t := time.Now()
switch {
case t.Hour() < 12:
    fmt.Println("It's before noon")
default:
    fmt.Println("It's after noon")
}

sama dengan menulis ini:

t := time.Now()
if t.Hour() < 12 {
    fmt.Println("It's before noon")
} else {
    fmt.Println("It's after noon")
}

Anda dapat membaca lebih lanjut di sini .

Shashank Goyal
sumber
0

Rune adalah nilai int32, dan karenanya merupakan tipe Go yang digunakan untuk mewakili titik kode Unicode. Titik kode Unicode atau posisi kode adalah nilai numerik yang biasanya digunakan untuk mewakili karakter Unicode tunggal;

Remario
sumber