O que é uma runa?


188

O que é uma rune in Go?

Eu tenho pesquisado no Google, mas Golang apenas diz em uma linha: runeé um apelido paraint32 .

Mas como os números inteiros são usados ​​ao redor, como trocar casos?

A seguir, uma caixa de troca de funções. O que é tudo <=e -?

E por que não switchtem argumentos?

&&deve significar e mas o que é 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
    }
}

A maioria deles é de http://play.golang.org/p/H6wjLZj6lW

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

Eu entendo que isso está mapeando runepara stringque ele possa retornar a string trocada. Mas eu não entendo como exatamente runeou bytefunciona aqui.


Sidenote: Isso não faz o que os leitores mais jovens podem querer fazer com a palavra em inglês "café" e outros - e muito menos em outros idiomas. O Go possui bibliotecas com suporte decente para variantes realmente úteis desse tipo de transformação.
RedGrittyBrick

2
No caso de alguém quer saber onde a palavra "runa" vieram de: en.wikipedia.org/wiki/Runic_(Unicode_block)
Matt Browne

A []runepode ser definido como um tipo booleano, numérico ou de sequência. Consulte stackoverflow.com/a/62739051/12817546 .
Tom J

Respostas:


149

Literais de runa são apenas valores inteiros de 32 bits ( no entanto, são constantes não tipadas, para que seu tipo possa ser alterado ). Eles representam pontos de código unicode. Por exemplo, o literal da runa 'a'é realmente o número97 .

Portanto, seu programa é 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'))
}

Deveria ser óbvio, se você observar o mapeamento Unicode, que é idêntico ao ASCII nesse intervalo. Além disso, 32 é de fato o deslocamento entre o ponto de código em maiúsculas e minúsculas do caractere. Então, adicionando 32a 'A', você obtém 'a'e vice-versa.


12
Obviamente, isso funciona apenas para caracteres ASCII e não para caracteres acentuados como 'ä', muito menos casos mais complicados como o 'ı' (U + 0131). O Go possui funções especiais para mapear para minúsculas, como unicode.ToLower(r rune) rune.
topskip

2
E para adicionar a resposta correta de @ topskip com uma função swapcase que funciona para todos os codepoints e não apenas az:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
ANisus

22
Runas são valores int32. Essa é a resposta completa. Eles não são "mapeados" .
Thwd 11/10

@AlixAxel: O comportamento do SimpleFold é essencialmente o mesmo (também usa ToLower e ToUpper para a maioria das runas). Existem alguns casos em que é diferente, como: DZ-> Dz, Dz-> dz, dz-> DZ. Meu SwapRune seria: DZ-> dz, Dz-> DZ, dz-> DZ. I como sua sugestão melhor :)
ANisus

3
Então, as runas são semelhantes aos caracteres C?
Kenny Worden 23/02

53

Nas notas de versão do Go lang: http://golang.org/doc/go1#rune

Rune é um tipo. Ocupa 32 bits e deve representar um CodePoint Unicode . Como analogia, o conjunto de caracteres em inglês codificado em 'ASCII' possui 128 pontos de código. Assim, é capaz de caber dentro de um byte (8 bits). A partir dessa suposição (incorreta), C tratava caracteres como 'bytes' e 'strings' como 'sequência de caracteres' .charchar*

Mas adivinhem. Existem muitos outros símbolos inventados por humanos além dos símbolos 'abcde ...'. E há tantos que precisamos de 32 bits para codificá-los.

Em golang, então a stringé uma sequência de bytes. No entanto, como vários bytes podem representar um ponto de código da runa, um valor de sequência também pode conter runas. Portanto, pode ser convertido em a []runeou vice-versa.

O pacote unicode http://golang.org/pkg/unicode/ pode dar uma amostra da riqueza do desafio.


6
Com o recente Unicode 6.3, existem mais de 110.000 símbolos definidos. Isso requer pelo menos uma representação de 21 bits de cada ponto de código, portanto, a runeé como int32e possui muitos bits.
21813 Rick-777 #

2
Você diz que "a stringé uma sequência de runes" - não acho que seja verdade? Vá ao blog : "uma string é apenas um monte de bytes"; Go lang especificação : "O valor de uma string é uma sequência (possivelmente vazio) de bytes"
Chris Martin

1
Ainda estou confuso, então a string é uma matriz de runas ou uma matriz de bytes? Eles são intercambiáveis?
Gogofan

1
@prvn Isso está errado. É como dizer que uma imagem não é uma sequência de bytes, é uma sequência de pixels. Mas, na verdade, por baixo, há uma série de bytes. Uma string é uma série de bytes, não runas. Por favor, leia as especificações .
Inanc Gumus

1
@prvn Mas, você não pode dizer not bytes. Então, você pode dizer: "As seqüências de caracteres são compostas de runas e runas de bytes". Algo assim. Então novamente. não é completamente verdade.
Inanc Gumus

28

Tentei manter minha linguagem simples para que um leigo entendesse rune.

Uma runa é um personagem. É isso aí.

É um único personagem. É um personagem de qualquer alfabeto, de qualquer idioma, de qualquer lugar do mundo.

Para obter uma string, usamos

double-quotes ""

OU

back-ticks ``

Uma string é diferente de uma runa. Nas runas usamos

single-quotes ''

Agora uma runa também é um pseudônimo para int32... O quê?

A razão pela qual rune é um alias int32é porque vemos que, com esquemas de codificação como abaixo insira a descrição da imagem aqui

cada personagem é mapeado para algum número e, portanto, é o número que estamos armazenando. Por exemplo, um mapeia para 97 e quando armazenamos esse número, é apenas o número e, assim, runa é um alias para int32. Mas não é apenas qualquer número. É um número com 32 'zeros e uns' ou '4' bytes. (Nota: UTF-8 é um esquema de codificação de 4 bytes)

Como as runas se relacionam com as strings?

Uma string é uma coleção de runas. No código a seguir:

    package main

    import (
        "fmt"
    )

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

Tentamos converter uma string em um fluxo de bytes. A saída é:

[72 101 108 108 111]

Podemos ver que cada um dos bytes que compõem essa string é uma runa.


2
A string is not a collection of runesisso não está correto estritamente falando. Em vez disso, string é uma fatia de bytes, codificada com utf8. Cada caractere na string leva de 1 a 3 bytes, enquanto cada runa ocupa 4 bytes. Você pode converter entre string e [] runa, mas elas são diferentes.
Eric Wang

2
Rune não é um personagem, uma runa representa um ponto de código unicode. E um ponto de código não aponta necessariamente para um caractere.
Inanc Gumus 10/10

Vale acrescentar que "uma runa também é um pseudônimo para int32" sim, mas isso não significa que seja útil para a compactação de homens pobres ... Se você atingir algo como 55296, a conversão de cadeia se perderá: Go Playground
kubanczyk

27

Eu não tenho reputação suficiente para postar um comentário na resposta de fabrizioM , então terei que postá-lo aqui.

A resposta de Fabrizio está amplamente correta e ele certamente capturou a essência do problema - embora haja uma distinção que deve ser feita.

Uma string NÃO é necessariamente uma sequência de runas. É um invólucro sobre uma 'fatia de bytes', uma fatia sendo um wrapper sobre uma matriz Go. Que diferença isso faz?

Um tipo de runa é necessariamente um valor de 32 bits, o que significa que uma sequência de valores de tipos de runas necessariamente terá algum número de bits x * 32. As strings, sendo uma sequência de bytes, têm um comprimento de x * 8 bits. Se todas as strings estivessem realmente em Unicode, essa diferença não teria impacto. Como as seqüências de caracteres são fatias de bytes , o Go pode usar ASCII ou qualquer outra codificação de bytes arbitrária.

Literais de string, no entanto, precisam ser gravados na fonte codificada em UTF-8.

Fonte de informação: http://blog.golang.org/strings


1
Bom ponto! Cada runa requer 4 bytes, mas cada caractere na string é codificado com utf8, portanto, apenas 1 a 3 bytes no máximo.
Eric Wang

16

(Tenho a sensação de que as respostas acima ainda não indicam as diferenças e as relações entre stringe[]rune muito claramente, por isso, tentaria adicionar outra resposta com exemplo.)

Como @Strangeworka resposta disse, stringe[]rune são silenciosos diferentes.

Diferenças - string& []rune:

  • string valueé uma fatia de bytes somente leitura. E, uma string literal é codificada em utf-8. Cada char na stringverdade leva de 1 a 3 bytes, enquanto cada um runeleva 4 bytes
  • Pois string, both len()e index são baseados em bytes.
  • Pois []rune, both len()e index são baseados em runa (ou int32).

Relacionamentos - string& []rune:

  • Quando você converte de stringpara []rune, cada caractere utf-8 nessa sequência se torna a rune.
  • Da mesma forma, na conversão reversa, ao converter de []runepara string, cada runeum se torna um caracter utf-8 no string.

Dicas:

  • Você pode converter entre stringe []rune, mas eles ainda são diferentes, tanto no tipo quanto no tamanho geral.

(Eu adicionaria um exemplo para mostrar isso mais claramente.)


Código

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

Executar:

vá executar string_rune_compare.go

Resultado:

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

Explicação:

  • A cadeia hello你好tem comprimento 11, porque os primeiros 5 caracteres cada um levam apenas 1 byte, enquanto os últimos 2 caracteres chineses levam 3 bytes.

    • Portanto, total bytes = 5 * 1 + 2 * 3 = 11
    • Como len()a string é baseada em bytes, a primeira linha impressalen: 11
    • Como o índice na string também é baseado em bytes, as duas linhas a seguir imprimem valores do tipo uint8(já que byteé um tipo de alias de uint8, em movimento).
  • Ao converter stringpara []rune, ele encontrou 7 utf8 chars, assim 7 runas.

    • Como len()on []runeé baseado em runa, a última linha é impressa len: 7.
    • Se você operar []runevia índice, ele acessará a base na runa.
      Como cada runa é de um utf8 char na string original, também é possível dizer que a len()operação de ambos e o índice []runesão baseadas em utf8 chars.

"Para string, len () e index são baseados em bytes." Você poderia explicar isso um pouco mais? Quando faço fmt.Println("hello你好"[0])isso, retorna o ponto de código UTF-8 real em vez de bytes.
Julian

@ Julian Por favor, dê uma olhada na saída do programa na resposta, pois s[0], ele imprime s[0]: 104, type: uint8, o tipo é uint8, significa que é um byte. Para caracteres ASCII como hutf-8, use também um byte único para representá-lo; portanto, o ponto de código é o mesmo que o byte único; mas para caracteres chineses como , use 3 bytes.
Eric Wang

Exemplo esclarecedor. Eu citei você aqui stackoverflow.com/a/62739051/12817546 .
Tom J

7

Todo mundo já cobriu a parte relacionada às runas, então não vou falar sobre isso.

No entanto, há também uma pergunta relacionada a switchnão ter argumentos. Isso ocorre simplesmente porque em Golang, switchsem uma expressão, é uma maneira alternativa de expressar a lógica if / else. Por exemplo, escrevendo isso:

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

é o mesmo que escrever isso:

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

Você pode ler mais aqui .


0

Uma runa é um valor int32 e, portanto, é um tipo de Go usado para representar um ponto de código Unicode. Um ponto de código Unicode ou uma posição de código é um valor numérico geralmente usado para representar caracteres Unicode únicos;

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.