Qu'est-ce qu'une rune?

211

Qu'est-ce qu'un runein Go?

J'ai cherché sur Google mais Golang ne dit qu'en une seule ligne: runeest un alias pourint32 .

Mais comment se fait-il que les entiers soient utilisés partout comme des cas d'échange?

Ce qui suit est un cas d'échange de fonctions. Qu'est-ce que tout le <=et -?

Et pourquoi n'a pas switchd'arguments?

&&devrait signifier et mais qu'est-ce que c'est 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 plupart d'entre eux proviennent de http://play.golang.org/p/H6wjLZj6lW

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

Je comprends qu'il s'agit d'un mappage runevers stringafin qu'il puisse renvoyer la chaîne permutée. Mais je ne comprends pas comment exactement runeou bytefonctionne ici.

Quentin Gibson
la source
Note de bas de page: Cela ne fait pas ce que les jeunes lecteurs pourraient souhaiter qu'il fasse pour le mot anglais «café» et d' autres - sans parler d'autres langues. Go a des bibliothèques avec un support décent pour des variantes réellement utiles de ce type de transformation.
RedGrittyBrick
3
Au cas où quelqu'un voudrait savoir d'où vient le mot «rune»: en.wikipedia.org/wiki/Runic_(Unicode_block)
Matt Browne
A []runepeut être défini sur un type booléen, numérique ou chaîne. Voir stackoverflow.com/a/62739051/12817546 .
Tom L

Réponses:

165

Les littéraux runiques ne sont que des valeurs entières 32 bits ( mais ce sont des constantes non typées, leur type peut donc changer ). Ils représentent des points de code unicode. Par exemple, le littéral runique 'a'est en fait le nombre 97.

Par conséquent, votre programme équivaut à peu près à:

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

Cela devrait être évident, si vous regardez le mappage Unicode, qui est identique à ASCII dans cette plage. De plus, 32 est en fait le décalage entre les points de code majuscules et minuscules du caractère. Donc, en ajoutant 32à 'A', vous obtenez 'a'et vice versa.

topskip
la source
12
Cela ne fonctionne évidemment que pour les caractères ASCII et non pour les caractères accentués tels que «ä», sans parler des cas plus compliqués comme le «ı» (U + 0131). Go a des fonctions spéciales pour mapper aux minuscules telles que unicode.ToLower(r rune) rune.
topskip
3
Et pour ajouter à la réponse correcte de @ topskip avec une fonction SwapCase qui fonctionne pour tous les points de code et pas seulement az:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
ANisus
23
Les runes sont des valeurs int32. C'est toute la réponse. Ils ne sont pas «cartographiés» .
thwd
@AlixAxel: Le comportement de SimpleFold est essentiellement le même (il utilise également ToLower et ToUpper pour la plupart des runes). Il y a des cas où il diffère tels que: DZ-> Dz, Dz-> dz, dz-> DZ. Mon SwapRune irait plutôt: DZ-> dz, Dz-> DZ, dz-> DZ. J'aime mieux ta suggestion :)
ANisus
3
Les runes sont donc similaires aux caractères C?
Kenny Worden
58

Extrait des notes de publication de Go lang: http://golang.org/doc/go1#rune

Rune est un type. Il occupe 32 bits et est censé représenter un Unicode CodePoint . Par analogie, le jeu de caractères anglais codés en «ASCII» a 128 points de code. Ainsi est capable de tenir à l'intérieur d'un octet (8 bits). A partir de cette hypothèse (erronée), C a traité les caractères comme des «octets» charet les «chaînes» comme une «séquence de caractères» char*.

Mais devinez quoi. Il existe de nombreux autres symboles inventés par les humains autres que les symboles «abcde ..». Et il y en a tellement que nous avons besoin de 32 bits pour les encoder.

En golang, alors a stringest une séquence de bytes. Cependant, comme plusieurs octets peuvent représenter un point de code runique, une valeur de chaîne peut également contenir des runes. Ainsi, il peut être converti en a []rune, ou vice versa.

Le package unicode http://golang.org/pkg/unicode/ peut donner un avant-goût de la richesse du défi.

fabrizioM
la source
6
Avec le récent Unicode 6.3, plus de 110 000 symboles sont définis. Cela nécessite une représentation d'au moins 21 bits de chaque point de code, donc a runeest similaire int32et contient beaucoup de bits.
Rick-777
2
Vous dites "a stringest une séquence de runes" - je ne pense pas que ce soit vrai? Aller au blog : "une chaîne n'est qu'un tas d'octets"; Go lang spec : "Une valeur de chaîne est une séquence (éventuellement vide) d'octets"
Chris Martin
1
Je suis toujours confus, est-ce que la chaîne est un tableau de runes ou un tableau d'octets? Sont-ils interchangeables?
gogofan
1
@prvn C'est faux. C'est comme dire qu'une image n'est pas une séquence d'octets, c'est une séquence de pixels. Mais en fait, en dessous, c'est une série d'octets. Une chaîne est une série d'octets, pas de runes. Veuillez lire les spécifications .
Inanc Gumus
1
@prvn Mais, vous ne pouvez pas dire not bytes. Ensuite, vous pourriez dire: "Les chaînes sont constituées de runes et de runes d'octets" Quelque chose comme ça. Puis encore. ce n'est pas tout à fait vrai.
Inanc Gumus
33

J'ai essayé de garder mon langage simple pour qu'un profane le comprenne rune.

Une rune est un personnage. C'est ça.

C'est un personnage unique. C'est un caractère de n'importe quel alphabet de n'importe quelle langue de n'importe où dans le monde.

Pour obtenir une chaîne que nous utilisons

double-quotes ""

OU

back-ticks ``

Une chaîne est différente d'une rune. Dans les runes que nous utilisons

single-quotes ''

Maintenant, une rune est aussi un alias pour int32... Euh Quoi?

La raison pour laquelle rune est un alias pour int32est parce que nous voyons qu'avec des schémas de codage tels que ci-dessous entrez la description de l'image ici

chaque caractère correspond à un certain nombre et c'est donc le nombre que nous stockons. Par exemple, un correspond à 97 et lorsque nous stockons ce numéro, c'est juste le numéro et c'est ainsi que rune est un alias pour int32. Mais ce n'est pas n'importe quel nombre. C'est un nombre avec 32 «zéros et uns» ou «4» octets. (Remarque: UTF-8 est un schéma de codage sur 4 octets)

Comment les runes sont-elles liées aux cordes?

Une chaîne est une collection de runes. Dans le code suivant:

    package main

    import (
        "fmt"
    )

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

Nous essayons de convertir une chaîne en un flux d'octets. La sortie est:

[72 101 108 108 111]

Nous pouvons voir que chacun des octets qui composent cette chaîne est une rune.

Suhail Gupta
la source
4
A string is not a collection of runesce n'est pas exact à proprement parler. Au lieu de cela, string est une tranche d'octets, encodée avec utf8. Chaque caractère dans la chaîne prend en fait 1 à 3 octets, tandis que chaque rune prend 4 octets. Vous pouvez convertir entre une chaîne et une rune [], mais elles sont différentes.
Eric Wang
2
Rune n'est pas un personnage, une rune représente un point de code unicode. Et un point de code ne pointe pas nécessairement vers un caractère.
Inanc Gumus
Cela vaut la peine d'ajouter que "une rune est aussi un alias pour int32" oui, mais cela ne signifie pas que c'est utile pour la compression des pauvres ... Si vous frappez quelque chose comme 55296 la conversion de chaîne s'égare: Go Playground
kubanczyk
30

Je n'ai pas assez de réputation pour publier un commentaire sur la réponse de fabrizioM , je vais donc devoir le poster ici à la place.

La réponse de Fabrizio est en grande partie correcte et il a certainement saisi l'essence du problème - bien qu'il y ait une distinction à faire.

Une chaîne n'est PAS nécessairement une séquence de runes. C'est un wrapper sur une «tranche d'octets», une tranche étant un wrapper sur un tableau Go. Quelle différence cela fait-il?

Un type de rune est nécessairement une valeur de 32 bits, ce qui signifie qu'une séquence de valeurs de types de runes aurait nécessairement un certain nombre de bits x * 32. Les chaînes, qui sont une séquence d'octets, ont à la place une longueur de x * 8 bits. Si toutes les chaînes étaient réellement en Unicode, cette différence n'aurait aucun impact. Cependant, comme les chaînes sont des tranches d'octets , Go peut utiliser ASCII ou tout autre codage d'octets arbitraire.

Cependant, les littéraux de chaîne doivent être écrits dans la source codée en UTF-8.

Source d'informations: http://blog.golang.org/strings

Strangework
la source
1
Bon point ! Chaque rune nécessite 4 octets, mais chaque caractère de la chaîne est encodé avec utf8, donc seulement 1 à 3 octets au maximum.
Eric Wang
19

(J'ai le sentiment que les réponses ci-dessus n'indiquent toujours pas les différences et les relations entre stringet []runetrès clairement, alors j'essaierais d'ajouter une autre réponse avec un exemple.)

Comme @Strangeworkl'a dit la réponse, stringet []runesont calmes différents.

Différences - string& []rune:

  • string valueest une tranche d'octets en lecture seule. Et, une chaîne littérale est codée en utf-8. Chaque caractère stringprend en fait 1 à 3 octets, tandis que chacun runeprend 4 octets
  • Pour string, les deux len()et index sont basés sur des octets.
  • Pour []rune, les deux len()et index sont basés sur rune (ou int32).

Relations - string& []rune:

  • Lorsque vous convertissez de stringen []rune, chaque caractère utf-8 de cette chaîne devient un rune.
  • De même, dans la conversion inverse, lors de la conversion de []runeen string, chacun runedevient un caractère utf-8 dans le fichier string.

Conseils:

  • Vous pouvez convertir entre stringet []rune, mais ils sont toujours différents, à la fois dans le type et la taille globale.

(J'ajouterais un exemple pour le montrer plus clairement.)


Code

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

Exécuter:

lancez string_rune_compare.go

Production:

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

Explication:

  • La chaîne hello你好a une longueur de 11, car les 5 premiers caractères prennent chacun 1 octet seulement, tandis que les 2 derniers caractères chinois prennent chacun 3 octets.

    • Donc, total bytes = 5 * 1 + 2 * 3 = 11
    • Puisque la len()chaîne est basée sur des octets, la première ligne est donc impriméelen: 11
    • Puisque l'index sur la chaîne est également basé sur des octets, les 2 lignes suivantes impriment des valeurs de type uint8(puisque bytec'est un type d'alias de uint8, in go).
  • Lors de la conversion du stringto []rune, il a trouvé 7 caractères utf8, donc 7 runes.

    • Puisque len()on []runeest basé sur la rune, donc la dernière ligne est imprimée len: 7.
    • Si vous opérez []runevia index, il accédera à la base sur la rune.
      Étant donné que chaque rune provient d'un caractère utf8 dans la chaîne d'origine, vous pouvez donc également dire que les deux len()et les opérations d'indexation []runesont basées sur les caractères utf8.
Eric Wang
la source
"Pour la chaîne, len () et index sont basés sur des octets." Pouvez-vous expliquer cela un peu plus? Quand je le fais, fmt.Println("hello你好"[0])cela renvoie le point de code UTF-8 réel au lieu d'octets.
Julian
@Julian Veuillez jeter un oeil à la sortie du programme dans la réponse, car s[0], il affiche s[0]: 104, type: uint8, le type est uint8, signifie que c'est un octet. Pour les caractères ASCII comme hutf-8, utilisez également un seul octet pour le représenter, de sorte que le point de code est le même que l'octet unique; mais pour les caractères chinois comme , il utilise 3 octets.
Eric Wang
Exemple clarifiant. Je vous ai cité ici stackoverflow.com/a/62739051/12817546 .
Tom L
7

Tout le monde a couvert la partie liée aux runes, donc je ne vais pas en parler.

Cependant, il y a aussi une question liée au fait de switchne pas avoir d'arguments. C'est simplement parce que dans Golang, switchsans expression est une autre façon d'exprimer la logique if / else. Par exemple, en écrivant ceci:

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

équivaut à écrire ceci:

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

Vous pouvez en savoir plus ici .

Shashank Goyal
la source
1

Une rune est une valeur int32 et, par conséquent, il s'agit d'un type Go utilisé pour représenter un point de code Unicode. Un point de code Unicode ou une position de code est une valeur numérique généralement utilisée pour représenter des caractères Unicode uniques;

Remario
la source