¿Qué es una runa?

188

Que es un rune en Go?

He estado buscando en Google pero Golang solo dice en una línea: runees un alias paraint32 .

Pero, ¿cómo es que los enteros se usan por todas partes como casos de intercambio?

El siguiente es un intercambio de funciones. ¿Qué es todo el <=y- ?

¿Y por qué no switchtiene ningún argumento?

&&debería significar y ¿pero qué es 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 mayoría de ellos son de http://play.golang.org/p/H6wjLZj6lW

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

Entiendo que esto es mapeo runepara stringque pueda devolver la cadena intercambiada. Pero no entiendo cómo exactamente runeo bytefunciona aquí.

Quentin Gibson
fuente
Nota al margen: Esto no hace lo que los lectores más jóvenes podrían querer que haga por la palabra en inglés "café" y otros, y mucho menos otros idiomas. Go tiene bibliotecas con un soporte decente para variantes realmente útiles de este tipo de transformación.
RedGrittyBrick
2
En caso de que alguien quiera saber de dónde proviene la palabra "runa": en.wikipedia.org/wiki/Runic_(Unicode_block)
Matt Browne
A []runese puede establecer en un tipo booleano, numérico o de cadena. Ver stackoverflow.com/a/62739051/12817546 .
Tom J

Respuestas:

149

Los literales de runas son solo valores enteros de 32 bits ( sin embargo, son constantes sin tipo, por lo que su tipo puede cambiar ). Representan puntos de código unicode. Por ejemplo, el literal de la runa 'a'es en realidad el número97 .

Por lo tanto, su programa es más o menos 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'))
}

Debería ser obvio, si tuviera que mirar la asignación Unicode, que es idéntica a ASCII en ese rango. Además, 32 es de hecho el desplazamiento entre el punto de código en mayúsculas y minúsculas del carácter. Entonces, agregando 32a 'A', obtienes 'a'y viceversa.

topskip
fuente
12
Obviamente, esto solo funciona para caracteres ASCII y no para caracteres accedidos como 'ä', y mucho menos para casos más complicados como 'ı' (U + 0131). Go tiene funciones especiales para asignar a minúsculas como unicode.ToLower(r rune) rune.
topskip
2
Y para agregar a la respuesta correcta de @ topskip con una función SwapCase que funciona para todos los puntos de código y no solo az:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
ANisus
22
Las runas son valores int32. Esa es toda la respuesta. No están "mapeados" .
thwd
@AlixAxel: el comportamiento de SimpleFold es esencialmente el mismo (también usa ToLower y ToUpper para la mayoría de las runas). Hay algunos casos en los que difiere, como: DZ-> Dz, Dz-> dz, dz-> DZ. Mi SwapRune en cambio iría: DZ-> dz, Dz-> DZ, dz-> DZ. Me gusta más tu sugerencia :)
ANisus
3
Entonces, ¿las runas son similares a los caracteres C?
Kenny Worden
53

De las notas de la versión de Go Lang: http://golang.org/doc/go1#rune

La runa es un tipo. Ocupa 32 bits y está destinado a representar un CodePoint Unicode . Como analogía, el conjunto de caracteres en inglés codificado en 'ASCII' tiene 128 puntos de código. Por lo tanto, puede caber dentro de un byte (8 bits). De esta suposición (errónea) C trató los caracteres como 'bytes' y 'cadenas' como una 'secuencia de caracteres' .charchar*

Pero adivina que. Hay muchos otros símbolos inventados por los humanos además de los símbolos 'abcde ...'. Y hay tantos que necesitamos 32 bits para codificarlos.

En golang, a stringes una secuencia de bytes. Sin embargo, dado que varios bytes pueden representar un punto de código de runas, un valor de cadena también puede contener runas. Por lo tanto, se puede convertir a a []rune, o viceversa.

El paquete unicode http://golang.org/pkg/unicode/ puede dar una idea de la riqueza del desafío.

fabrizioM
fuente
66
Con el reciente Unicode 6.3, hay más de 110,000 símbolos definidos. Esto requiere al menos una representación de 21 bits de cada punto de código, por lo que a runees como int32y tiene muchos bits.
Rick-777
2
Dices "a stringes una secuencia de runes". ¿No creo que sea cierto? Ir al blog : "una cadena es solo un montón de bytes"; Ir a la especificación lang : "Un valor de cadena es una secuencia (posiblemente vacía) de bytes"
Chris Martin
1
Todavía estoy confundido, entonces, ¿es una serie de runas o una serie de bytes? ¿Son intercambiables?
gogofan
1
@prvn Eso está mal. Es como decir que una imagen no es una secuencia de bytes, es una secuencia de píxeles. Pero, en realidad, debajo, hay una serie de bytes. Una cadena es una serie de bytes, no runas. Por favor lea las especificaciones .
Inanc Gumus
1
@prvn Pero no puedes decirlo not bytes. Entonces, podría decir: "Las cadenas están formadas por runas y las runas formadas por bytes" Algo así. Entonces otra vez. No es del todo cierto.
Inanc Gumus
28

He tratado de mantener mi lenguaje simple para que un laico entienda rune.

Una runa es un personaje. Eso es.

Es un solo personaje. Es un personaje de cualquier alfabeto de cualquier idioma desde cualquier parte del mundo.

Para obtener una cadena usamos

double-quotes ""

O

back-ticks ``

Una cadena es diferente a una runa. En runas usamos

single-quotes ''

Ahora una runa es también un alias para int32... ¿Qué?

La razón por la que las runas son un alias int32es porque vemos que con esquemas de codificación como los siguientes ingrese la descripción de la imagen aquí

cada personaje se asigna a algún número y, por lo tanto, es el número que estamos almacenando. Por ejemplo, un mapeo a 97 y cuando almacenamos ese número es solo el número y así es como la runa es un alias para int32. Pero no es un número cualquiera. Es un número con 32 'ceros y unos' o '4' bytes. (Nota: UTF-8 es un esquema de codificación de 4 bytes)

¿Cómo se relacionan las runas con las cuerdas?

Una cadena es una colección de runas. En el siguiente código:

    package main

    import (
        "fmt"
    )

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

Intentamos convertir una cadena en una secuencia de bytes. El resultado es:

[72 101 108 108 111]

Podemos ver que cada uno de los bytes que conforman esa cadena es una runa.

Suhail Gupta
fuente
2
A string is not a collection of runesEsto no es correcto estrictamente hablando. En cambio, la cadena es un segmento de bytes, codificado con utf8. Cada char en cadena realmente toma 1 ~ 3 bytes, mientras que cada runa toma 4 bytes. Puede convertir entre string y [] rune, pero son diferentes.
Eric Wang
2
La runa no es un personaje, una runa representa un punto de código unicode. Y un punto de código no necesariamente apunta a un personaje.
Inanc Gumus
Vale la pena agregar que "una runa también es un alias para int32" sí, pero eso no significa que sea útil para la compresión de los pobres ... Si golpeas algo como 55296, la conversión de la cadena se desvía: Go Playground
kubanczyk
27

No tengo suficiente reputación para publicar un comentario a la respuesta de fabrizioM , por lo que tendré que publicarlo aquí.

La respuesta de Fabrizio es en gran medida correcta, y ciertamente captó la esencia del problema, aunque hay que hacer una distinción.

Una cadena NO es necesariamente una secuencia de runas. Es un contenedor sobre un 'segmento de bytes', un segmento es un contenedor sobre una matriz Go. ¿Qué diferencia hace esto?

Un tipo de runas es necesariamente un valor de 32 bits, lo que significa que una secuencia de valores de tipos de runas necesariamente tendría algún número de bits x * 32. Las cadenas, que son una secuencia de bytes, tienen una longitud de x * 8 bits. Si todas las cadenas estuvieran realmente en Unicode, esta diferencia no tendría ningún impacto. Sin embargo, dado que las cadenas son segmentos de bytes , Go puede usar ASCII o cualquier otra codificación de bytes arbitraria.

Sin embargo, los literales de cadena deben escribirse en la fuente codificada en UTF-8.

Fuente de información: http://blog.golang.org/strings

Trabajo extraño
fuente
1
Buen punto ! Cada runa requiere 4 bytes, pero cada carácter de la cadena está codificado con utf8, por lo tanto, solo 1 ~ 3 bytes como máximo.
Eric Wang
16

(Tenía la sensación de que las respuestas anteriores todavía no indicaban las diferencias y las relaciones entre ellas stringy []runemuy claramente, por lo que trataría de agregar otra respuesta con un ejemplo).

Como @Strangeworkdecía la respuesta, stringy []runeson silenciosamente diferentes.

Diferencias - string& []rune:

  • string valuees un segmento de byte de solo lectura. Y, un literal de cadena está codificado en utf-8. Cada char en stringrealidad toma 1 ~ 3 bytes, mientras que cada runetoma 4 bytes
  • Para string, ambos len()y el índice se basan en bytes.
  • Para []rune, ambos len()y el índice se basan en runas (o int32).

Relaciones - stringy []rune:

  • Cuando convierte de stringa []rune, cada carácter utf-8 en esa cadena se convierte en a rune.
  • Del mismo modo, en la conversión inversa, cuando se convierte de []runea string, cada uno se runeconvierte en un carácter utf-8 en el string.

Consejos:

  • Puede convertir entre stringy []rune, pero aún así son diferentes, tanto en tipo como en tamaño general.

(Añadiría un ejemplo para mostrarlo más 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()
}

Ejecutar:

ir a ejecutar string_rune_compare.go

Salida:

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

Explicación:

  • La cadena hello你好tiene una longitud de 11, porque los primeros 5 caracteres toman cada uno solo 1 byte, mientras que los últimos 2 caracteres chinos toman 3 bytes cada uno.

    • Así, total bytes = 5 * 1 + 2 * 3 = 11
    • Como la len()cadena se basa en bytes, la primera línea impresalen: 11
    • Dado que el índice en la cadena también se basa en bytes, las siguientes 2 líneas imprimen valores de tipo uint8(ya que bytees un tipo de alias uint8, in go).
  • Al convertir el stringa []rune, encontró 7 caracteres utf8, por lo tanto, 7 runas.

    • Dado que len()en []runese basa en la runa, por lo tanto, la última línea impresa len: 7.
    • Si opera a []runetravés del índice, accederá a la base en runas.
      Dado que cada runa es de un carácter utf8 en la cadena original, también puede decir que tanto la len()operación de índice como la []runebasada se basan en caracteres utf8.
Eric Wang
fuente
"Para la cadena, tanto len () como el índice se basan en bytes". ¿Podría explicar eso un poco más? Cuando lo hago fmt.Println("hello你好"[0]), devuelve el punto de código UTF-8 real en lugar de bytes.
Julian
@Julian Por favor, eche un vistazo a la salida del programa en la respuesta, ya que s[0]se imprime s[0]: 104, type: uint8, el tipo es uint8, significa que es un byte. Para caracteres ASCII como hutf-8 también use un solo byte para representarlo, por lo que el punto de código es el mismo que el byte único; pero para caracteres chinos como , usa 3 bytes.
Eric Wang
Ejemplo aclaratorio. Te cité aquí stackoverflow.com/a/62739051/12817546 .
Tom J
7

Todos los demás han cubierto la parte relacionada con las runas, así que no voy a hablar de eso.

Sin embargo, también hay una pregunta relacionada con switchno tener ningún argumento. Esto es simplemente porque en Golang, switchsin una expresión es una forma alternativa de expresar lógica if / else. Por ejemplo, escribiendo esto:

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

es lo mismo que escribir esto:

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

Puedes leer más aquí .

Shashank Goyal
fuente
0

Una runa es un valor int32 y, por lo tanto, es un tipo Go que se usa para representar un punto de código Unicode. Un punto de código Unicode o posición de código es un valor numérico que generalmente se usa para representar caracteres Unicode individuales;

Remario
fuente