Cos'è una runa?


188

Cos'è a runein Go?

Ho cercato su Google ma Golang dice solo in una riga: runeè un alias perint32 .

Ma come mai gli interi vengono usati ovunque come casi di scambio?

Di seguito è riportato uno swapcase di funzioni. Che cos'è tutto <=e -?

E perché non switchha argomenti?

&&dovrebbe significare e ma cos'è 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
    }
}

La maggior parte proviene da http://play.golang.org/p/H6wjLZj6lW

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

Capisco che questa sia la mappatura runein stringmodo che possa restituire la stringa scambiata. Ma non capisco come esattamente runeo bytefunzioni qui.


Sidenote: Questo non fa ciò che i lettori più giovani potrebbero desiderare che faccia per la parola inglese "café" e altri - per non parlare di altre lingue. Go ha librerie con un supporto decente per varianti effettivamente utili di questo tipo di trasformazione.
RedGrittyBrick

2
Nel caso qualcuno voglia sapere da dove viene la parola "runa": en.wikipedia.org/wiki/Runic_(Unicode_block)
Matt Browne,

A []runepuò essere impostato su un tipo booleano, numerico o stringa. Vedi stackoverflow.com/a/62739051/12817546 .
Tom J

Risposte:


149

I valori letterali delle rune sono solo valori interi a 32 bit ( tuttavia sono costanti non tipizzate, quindi il loro tipo può cambiare ). Rappresentano punti di codice unicode. Ad esempio, il valore letterale della runa 'a'è in realtà il numero 97.

Pertanto il tuo programma è praticamente equivalente a:

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'))
}

Dovrebbe essere ovvio, se dovessi guardare la mappatura Unicode, che è identica a ASCII in quell'intervallo. Inoltre, 32 è in effetti lo scostamento tra il punto di codice maiuscolo e minuscolo del carattere. Quindi aggiungendo 32a 'A', ottieni 'a'e viceversa.


12
Questo ovviamente funziona solo per i caratteri ASCII e non per i personaggi accesi come 'ä', per non parlare di casi più complicati come 'ı' (U + 0131). Go ha funzioni speciali per mappare in minuscole come unicode.ToLower(r rune) rune.
topskip

2
E da aggiungere alla risposta corretta di @ topskip con una funzione SwapCase che funziona per tutti i punti di codice e non solo per az:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
ANisus

22
Le rune sono valori int32. Questa è l'intera risposta. Non sono "mappati" .
giovedì

@AlixAxel: il comportamento di SimpleFold è essenzialmente lo stesso (utilizza anche ToLower e ToUpper per la maggior parte delle rune). Ci sono alcuni casi in cui differisce come: DZ-> Dz, Dz-> dz, dz-> DZ. La mia SwapRune andrebbe invece: DZ-> dz, Dz-> DZ, dz-> DZ. Mi piace di più il tuo suggerimento :)
ANisus,

3
Quindi le rune sono simili ai caratteri C?
Kenny Worden,

53

Dalle note sulla versione di Go lang: http://golang.org/doc/go1#rune

Rune è un tipo. Occupa 32 bit ed è pensato per rappresentare un Unicode CodePoint . Come analogia, i caratteri inglesi impostati in 'ASCII' hanno 128 punti di codice. Quindi è in grado di adattarsi all'interno di un byte (8 bit). Da questo (errato) presupposto C trattò i caratteri come "byte" chare "stringhe" come una "sequenza di caratteri" char*.

Ma indovina un po. Esistono molti altri simboli inventati dagli umani oltre ai simboli "abcde ..". E ce ne sono così tanti che abbiamo bisogno di 32 bit per codificarli.

A Golang quindi a stringè una sequenza di bytes. Tuttavia, poiché più byte possono rappresentare un punto di codice rune, un valore di stringa può contenere anche rune. Quindi, può essere convertito in a []rune, o viceversa.

Il pacchetto unicode http://golang.org/pkg/unicode/ può dare un assaggio della ricchezza della sfida.


6
Con il recente Unicode 6.3, ci sono oltre 110.000 simboli definiti. Ciò richiede una rappresentazione di almeno 21 bit di ciascun punto di codice, quindi un runeè simile int32e ha molti bit.
Rick-777,

2
Dici "a stringè una sequenza di runes" - Non penso sia vero? Vai al blog : "una stringa è solo un mucchio di byte"; Go lang spec : "Un valore di stringa è una sequenza (possibilmente vuota) di byte"
Chris Martin,

1
Sono ancora confuso, quindi la stringa è una matrice di rune o una matrice di byte? Sono intercambiabili?
Gogofan,

1
@prvn È sbagliato. È come dire che un'immagine non è una sequenza di byte, è una sequenza di pixel. Ma, in realtà, sotto c'è una serie di byte. Una stringa è una serie di byte, non di rune. Si prega di leggere le specifiche .
Inanc Gumus,

1
@prvn Ma non puoi dirlo not bytes. Quindi, potresti dire: "Le stringhe sono composte da rune e rune composte da byte" Qualcosa del genere. Poi nuovamente. non è del tutto vero.
Inanc Gumus,

28

Ho cercato di mantenere la mia lingua semplice in modo che un laico capisca rune.

Una runa è un personaggio. Questo è tutto.

È un singolo personaggio. È un personaggio di qualsiasi alfabeto di qualsiasi lingua da qualsiasi parte del mondo.

Per ottenere una stringa che usiamo

double-quotes ""

O

back-ticks ``

Una stringa è diversa da una runa. Nelle rune usiamo

single-quotes ''

Ora una runa è anche un alias per int32... Uh Cosa?

La ragione per cui la runa è un alias int32è perché lo vediamo con schemi di codifica come di seguito inserisci qui la descrizione dell'immagine

ogni personaggio è mappato su un numero e quindi è il numero che stiamo memorizzando. Ad esempio, una mappa su 97 e quando memorizziamo quel numero è solo il numero e quindi questa runa è un alias per int32. Ma non è solo un numero qualsiasi. È un numero con 32 "zeri e uno" o "4" byte. (Nota: UTF-8 è uno schema di codifica a 4 byte)

Come si collegano le rune alle corde?

Una stringa è una raccolta di rune. Nel seguente codice:

    package main

    import (
        "fmt"
    )

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

Proviamo a convertire una stringa in un flusso di byte. L'output è:

[72 101 108 108 111]

Possiamo vedere che ciascuno dei byte che compongono quella stringa è una runa.


2
A string is not a collection of runesquesto non è corretto in senso stretto. Invece, string è una porzione di byte, codificata con utf8. Ogni carattere nella stringa richiede in realtà 1 ~ 3 byte, mentre ogni runa richiede 4 byte. Puoi convertire tra stringa e [] runa, ma sono diverse.
Eric Wang,

2
La runa non è un personaggio, una runa rappresenta un punto di codice unicode. E un punto di codice non indica necessariamente un carattere.
Inanc Gumus,

Vale la pena aggiungere che "una runa è anche un alias per int32" sì, ma ciò non significa che sia utile per la compressione dei poveri ... Se colpisci qualcosa come 55296 la conversione delle stringhe va fuori strada: Go Playground
kubanczyk

27

Non ho abbastanza reputazione per pubblicare un commento alla risposta di fabrizioM , quindi dovrò pubblicarlo qui.

La risposta di Fabrizio è in gran parte corretta e certamente ha colto l'essenza del problema, anche se c'è una distinzione che deve essere fatta.

Una stringa NON è necessariamente una sequenza di rune. È un wrapper su una 'fetta di byte', una fetta è un wrapper su un array Go. Che differenza fa?

Un tipo di runa è necessariamente un valore a 32 bit, il che significa che una sequenza di valori di tipi di runa avrebbe necessariamente un numero di bit x * 32. Le stringhe, essendo una sequenza di byte, hanno invece una lunghezza di x * 8 bit. Se tutte le stringhe fossero effettivamente in Unicode, questa differenza non avrebbe alcun impatto. Poiché le stringhe sono sezioni di byte , tuttavia, Go può utilizzare ASCII o qualsiasi altra codifica di byte arbitraria.

I letterali stringa, tuttavia, devono essere scritti nella sorgente codificata in UTF-8.

Fonte di informazioni: http://blog.golang.org/strings


1
Buon punto! Ogni runa richiede 4 byte, ma ogni carattere nella stringa è codificato con utf8, quindi solo 1 ~ 3 byte al massimo.
Eric Wang,

16

(Ho avuto la sensazione che le risposte di cui sopra ancora non indicassero le differenze e le relazioni tra stringe []runemolto chiaramente, quindi proverei ad aggiungere un'altra risposta con l'esempio.)

Come @Strangeworkdetto la risposta, stringe []runesono abbastanza diversi.

Differenze - string& []rune:

  • string valueè una porzione di byte di sola lettura. E, una stringa letterale è codificata in utf-8. Ogni char in stringeffettivamente richiede 1 ~ 3 byte, mentre ciascuno runerichiede 4 byte
  • Per string, sia len()e indice sono basati su byte.
  • Per []rune, sia len()e indice sono basati su rune (o int32).

Relazioni - string& []rune:

  • Quando converti da stringin []rune, ogni carattere utf-8 in quella stringa diventa a rune.
  • Allo stesso modo, nella conversione inversa, quando convertito da []runein string, ognuno runediventa un carattere utf-8 in string.

Suggerimenti:

  • Puoi convertire tra stringe []rune, ma sono comunque diversi, sia per tipo che per dimensione complessiva.

(Vorrei aggiungere un esempio per mostrarlo più chiaramente.)


Codice

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()
}

Eseguire:

vai a eseguire string_rune_compare.go

Produzione:

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

Spiegazione:

  • La stringa hello你好ha lunghezza 11, perché i primi 5 caratteri richiedono ciascuno solo 1 byte, mentre gli ultimi 2 caratteri cinesi richiedono ciascuno 3 byte.

    • Così, total bytes = 5 * 1 + 2 * 3 = 11
    • Poiché len()on string si basa sui byte, viene quindi stampata la prima rigalen: 11
    • Poiché anche l'indice su stringa si basa su byte, le seguenti 2 righe stampano valori di tipo uint8(poiché byteè un tipo alias di uint8, in go).
  • Quando ha convertito stringin []rune, ha trovato 7 caratteri utf8, quindi 7 rune.

    • Poiché len()su []runesi basa sulla runa, quindi l'ultima riga stampata len: 7.
    • Se operi []runetramite indice, accederà alla base su una runa.
      Poiché ogni runa proviene da un carattere utf8 nella stringa originale, quindi puoi anche dire che entrambe le len()operazioni e l'indice su []runesono basate su caratteri utf8.

"Per string, sia len () che index sono basati su byte." Potresti spiegarlo un po 'di più? Quando lo faccio fmt.Println("hello你好"[0])restituisce il vero punto di codice UTF-8 anziché i byte.
Giuliano,

@Julian Per favore dai un'occhiata all'output del programma nella risposta, perché s[0], stampa s[0]: 104, type: uint8, il tipo è uint8, significa che è un byte. Per i caratteri ASCII come hutf-8 anche usare un singolo byte per rappresentarlo, quindi il punto di codice è lo stesso del singolo byte; ma per i caratteri cinesi come , usa 3 byte.
Eric Wang,

Esempio di chiarimento. Ti ho citato qui stackoverflow.com/a/62739051/12817546 .
Tom J

7

Tutti gli altri hanno coperto la parte relativa alle rune, quindi non ne parlerò.

Tuttavia, esiste anche una domanda relativa alla switchmancanza di argomenti. Questo semplicemente perché in Golang, switchsenza un'espressione è un modo alternativo per esprimere la logica if / else. Ad esempio, scrivendo questo:

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

è come scrivere questo:

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

Puoi leggere di più qui .


0

Una runa è un valore int32, quindi è un tipo Go utilizzato per rappresentare un punto di codice Unicode. Un punto di codice Unicode o posizione di codice è un valore numerico che viene solitamente utilizzato per rappresentare singoli caratteri Unicode;

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.