Co to jest runa?

188

Co to jest runew Go?

Googlowałem, ale Golang mówi tylko w jednym wierszu: runeto pseudonimint32 .

Ale w jaki sposób liczby całkowite są używane dookoła, jak zamiana przypadków?

Poniżej wymieniono funkcję wymiany. Co to wszystko <=i -?

A dlaczego nie switchma żadnych argumentów?

&&powinno znaczyć i co to jest 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
    }
}

Większość z nich pochodzi z http://play.golang.org/p/H6wjLZj6lW

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

Rozumiem, że to jest mapowanie, runeaby stringmogło zwrócić zamieniony ciąg. Ale nie rozumiem, jak dokładnie runelub bytetutaj działa.

Quentin Gibson
źródło
Sidenote: To nie robi tego, co młodsi czytelnicy chcieliby zrobić dla angielskiego słowa „kawiarnia” i innych - nie mówiąc już o innych językach. Go ma biblioteki z przyzwoitą obsługą naprawdę użytecznych wariantów tego rodzaju transformacji.
RedGrittyBrick
2
Na wypadek, gdyby ktoś chciał wiedzieć, skąd pochodzi słowo „runa”: en.wikipedia.org/wiki/Runic_(Unicode_block)
Matt Browne
[]runeMożna ustawić w logicznym, cyfry lub typu string. Zobacz stackoverflow.com/a/62739051/12817546 .
Tom J

Odpowiedzi:

149

Dosłowne oznaczenia run to tylko 32-bitowe wartości całkowite ( jednak są to stałe bez typu, więc ich typ może się zmienić ). Reprezentują punkty kodowe Unicode. Na przykład dosłowny znak runiczny 'a'jest w rzeczywistości liczbą 97.

Dlatego twój program jest prawie równoważny z:

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

Powinno być oczywiste, jeśli spojrzysz na mapowanie Unicode, które jest identyczne z ASCII w tym zakresie. Co więcej, 32 jest w rzeczywistości przesunięciem między wielkimi i małymi literami znaku. Więc dodając 32do 'A', dostajesz 'a'i na odwrót.

topskip
źródło
12
Działa to oczywiście tylko dla znaków ASCII, a nie dla znaków akcentowanych, takich jak „ä”, nie mówiąc już o bardziej skomplikowanych przypadkach, takich jak „ı” (U + 0131). Go ma specjalne funkcje mapowania na małe litery, takie jak unicode.ToLower(r rune) rune.
topskip
2
I dodać do poprawnej odpowiedzi @ topskip za pomocą funkcji SwapCase, która działa dla wszystkich współrzędnych kodowych, a nie tylko z:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
ANisus
22
Runy są wartościami int32. To jest cała odpowiedź. Nie są „mapowane” .
thwd
@AlixAxel: Zachowanie SimpleFold jest zasadniczo takie samo (używa również ToLower i ToUpper dla większości run). Istnieją pewne przypadki, w których się różni, takie jak: DZ-> Dz, Dz-> dz, dz-> DZ. Zamiast tego moja SwapRune: DZ-> dz, Dz-> DZ, dz-> DZ.
Bardziej
3
Więc runy są podobne do znaków C?
Kenny Worden
53

Informacje o wydaniu Go lang: http://golang.org/doc/go1#rune

Runa jest typem. Zajmuje 32 bity i ma reprezentować Unicode CodePoint . Analogicznie zestaw angielskich znaków zakodowanych w „ASCII” ma 128 punktów kodowych. Dzięki temu może zmieścić się w bajcie (8 bitów). Z tego (błędnego) założenia C traktował znaki jako „bajty” char, a „łańcuchy” jako „sekwencję znaków” char*.

Ale zgadnij co. Istnieje wiele innych symboli wymyślonych przez ludzi innych niż symbole „abcde ..”. Jest ich tak wiele, że potrzebujemy 32 bitów, aby je zakodować.

W golang a stringjest ciągiem bytes. Ponieważ jednak wiele bajtów może reprezentować runiczny punkt kodowy, wartość ciągu może również zawierać runy. Tak więc można go przekonwertować na a []runelub odwrotnie.

Pakiet Unicode http://golang.org/pkg/unicode/ może zasmakować bogactwa wyzwania.

fabrizioM
źródło
6
W najnowszym Unicode 6.3 zdefiniowano ponad 110 000 symboli. Wymaga to co najmniej 21-bitowej reprezentacji każdego punktu kodowego, więc a runejest podobne int32i ma wiele bitów.
Rick-777,
2
Mówisz „a stringjest sekwencją runes” - nie sądzę, że to prawda? Przejdź do blogu : „ciąg znaków to tylko kilka bajtów”; Go lang spec : „Wartość ciągu to (prawdopodobnie pusta) sekwencja bajtów”
Chris Martin
1
Nadal jestem zdezorientowany, więc czy ciąg znaków jest tablicą run lub tablicą bajtów? Czy są wymienne?
gogofan,
1
@prvn To źle. To tak, jakby powiedzieć, że obraz nie jest sekwencją bajtów, lecz sekwencją pikseli. Ale tak naprawdę pod spodem jest seria bajtów. Ciąg jest ciągiem bajtów, a nie run. Proszę przeczytać specyfikację .
Inanc Gumus
1
@prvn Ale nie możesz powiedzieć not bytes. Następnie możesz powiedzieć: „Ciągi składają się z run, a runy składają się z bajtów” Coś w tym stylu. Potem znowu. to nie do końca prawda.
Inanc Gumus
28

Starałem się, aby mój język był prosty, aby laik zrozumiał rune.

Runa jest postacią. Otóż ​​to.

To jest jedna postać. To znak z dowolnego alfabetu z dowolnego języka z dowolnego miejsca na świecie.

Aby uzyskać ciąg, którego używamy

double-quotes ""

LUB

back-ticks ``

Sznurek jest inny niż runa. W runach używamy

single-quotes ''

Teraz runa jest także pseudonimem int32... Co?

Powodem, dla którego runa jest aliasem, int32jest to, że widzimy to w schematach kodowania, takich jak poniżej wprowadź opis zdjęcia tutaj

każda postać przypisana jest do pewnej liczby, a więc jest to liczba, którą przechowujemy. Na przykład, mapuje do 97 i kiedy zapisać ten numer to tylko liczba, a więc to sposób runa jest aliasem dla Int32. Ale to nie tylko liczba. Jest to liczba składająca się z 32 „zer i jedynek” lub „4” bajtów. (Uwaga: UTF-8 to 4-bajtowy schemat kodowania)

Jak runy odnoszą się do sznurków?

Ciąg to zbiór run. W następującym kodzie:

    package main

    import (
        "fmt"
    )

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

Próbujemy przekonwertować ciąg znaków na strumień bajtów. Dane wyjściowe to:

[72 101 108 108 111]

Widzimy, że każdy z bajtów tworzących ten ciąg jest runą.

Suhail Gupta
źródło
2
A string is not a collection of runesnie jest to ściśle ściśle mówiąc. Zamiast tego ciąg jest wycięciem bajtu, zakodowanym za pomocą utf8. Każdy znak w ciągu zajmuje w rzeczywistości 1 ~ 3 bajty, podczas gdy każda runa zajmuje 4 bajty. Możesz konwertować między runą a [] runą, ale są one różne.
Eric Wang
2
Runa nie jest postacią, runa reprezentuje punkt kodowy Unicode. Punkt kodowy niekoniecznie wskazuje na jedną postać.
Inanc Gumus,
Warto dodać, że „runa to także pseudonim dla int32” tak, ale to nie znaczy, że jest przydatna w przypadku kompresji ubogich ... Jeśli trafisz coś takiego jak 55296, konwersja strun pójdzie na manowce: Go Playground
kubańczyk
27

Nie mam wystarczającej reputacji, aby opublikować komentarz do odpowiedzi fabrizioM , więc będę musiał go tutaj zamieścić.

Odpowiedź Fabrizio jest w dużej mierze poprawna i na pewno uchwycił istotę problemu - choć należy wprowadzić rozróżnienie.

Ciąg jest nie koniecznie sekwencja run. Jest to opakowanie nad „plasterkiem bajtów”, przy czym plaster jest opakowaniem nad tablicą Go. Jaką to robi różnicę?

Runa typu jest oczywiście wartość 32 bitów, co oznacza sekwencję wartości run rodzaju musiałyby mieć pewną liczbę bitów X * 32. Łańcuchy będące sekwencją bajtów mają zamiast tego długość x * 8 bitów. Gdyby wszystkie łańcuchy były w rzeczywistości w Unicode, różnica nie miałaby wpływu. Ponieważ łańcuchy są kawałkami bajtów , Go może jednak używać ASCII lub dowolnego innego kodowania bajtów.

Jednak literały łańcuchowe muszą być zapisane w źródle zakodowanym w UTF-8.

Źródło informacji: http://blog.golang.org/strings

Strangework
źródło
1
Słuszna uwaga ! Każda runa wymaga 4 bajtów, ale każdy znak w łańcuchu jest kodowany za pomocą utf8, a więc tylko 1 ~ 3 bajty.
Eric Wang
16

(Mam wrażenie, że powyższe odpowiedzi wciąż nie określały różnic i relacji między nimi, stringi []runebardzo wyraźnie, więc spróbuję dodać inną odpowiedź z przykładem).

Jak @Strangeworkpowiedziała odpowiedź, stringi []runesą cicho inni.

Różnice - stringi []rune:

  • string valuejest bajtem tylko do odczytu. I literał łańcuchowy jest zakodowany w utf-8. Każdy znak w stringrzeczywistości zajmuje 1 ~ 3 bajty, podczas gdy każdy runezajmuje 4 bajty
  • Dla stringobu len()indeks i są oparte na bajtach.
  • Bo []runezarówno len()indeks jak i oparte są na runie (lub int32).

Relacje - stringi []rune:

  • Kiedy konwertujesz z stringna []rune, każdy znak utf-8 w tym ciągu staje się rune.
  • Podobnie, w konwersji odwrotnej, po konwersji z []runena string, każdy runestaje się znakiem utf-8 w pliku string.

Wskazówki:

  • Możesz konwertować między stringi []rune, ale nadal są one różne, zarówno pod względem typu, jak i ogólnego rozmiaru.

(Dodałbym przykład, aby pokazać to jaśniej).


Kod

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

Wykonać:

idź uruchom string_rune_compare.go

Wynik:

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

Wyjaśnienie:

  • Ciąg hello你好ma długość 11, ponieważ każde pierwsze 5 znaków zajmuje tylko 1 bajt, a ostatnie 2 znaki chińskie - 3 bajty.

    • A zatem, total bytes = 5 * 1 + 2 * 3 = 11
    • Ponieważ len()ciąg jest oparty na bajtach, więc drukowany jest pierwszy wierszlen: 11
    • Ponieważ indeks na łańcuchu jest również oparty na bajtach, dlatego następujące 2 wiersze wypisują wartości typu uint8(ponieważ bytejest to alias typu uint8, in go).
  • Kiedy przekonwertować stringdo []rune, stwierdzono 7 znaków utf8, a więc 7 run.

    • Ponieważ len()on []runeopiera się na runie, więc drukowana jest ostatnia linia len: 7.
    • Jeśli operujesz []runeza pomocą indeksu, będzie on miał dostęp do bazy na runie.
      Ponieważ każda runa pochodzi z znaku utf8 w oryginalnym łańcuchu, możesz więc powiedzieć, że oba len()operacje na indeksie []runesą oparte na znakach utf8.
Eric Wang
źródło
„W przypadku łańcucha zarówno len (), jak i indeks są oparte na bajtach.” Czy mógłbyś to trochę wyjaśnić? Kiedy to robię fmt.Println("hello你好"[0]), zwraca rzeczywisty punkt kodowy UTF-8 zamiast bajtów.
Julian
@Julian Proszę spojrzeć na wynik programu w odpowiedzi s[0], ponieważ drukuje s[0]: 104, type: uint8, typ jest uint8, oznacza jego bajt. W przypadku znaków ASCII, takich jak hutf-8, również reprezentują go jeden bajt, więc punkt kodowy jest taki sam jak pojedynczy bajt; ale w przypadku chińskich znaków używa 3 bajtów.
Eric Wang
Przykład wyjaśniający. Zacytowałem cię tutaj stackoverflow.com/a/62739051/12817546 .
Tom J
7

Wszyscy inni opisali część związaną z runami, więc nie zamierzam o tym mówić.

Istnieje jednak pytanie związane z switchbrakiem argumentów. Jest tak po prostu dlatego, że w Golang switchbez wyrażenia jest alternatywnym sposobem wyrażenia logiki if / else. Na przykład pisząc to:

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

jest taki sam jak napisanie tego:

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

Możesz przeczytać więcej tutaj .

Shashank Goyal
źródło
0

Runa jest wartością int32, a zatem jest to typ Go używany do reprezentowania punktu kodowego Unicode. Punkt kodowy lub pozycja kodu Unicode to wartość liczbowa, która jest zwykle używana do reprezentowania pojedynczych znaków Unicode;

Remario
źródło