Что такое руна?

189

Что такое runeв го?

Я гуглил, но Голанг говорит только в одной строке: runeэто псевдоним дляint32 .

Но как же целые числа используются повсеместно, как случаи замены?

Ниже приведен раздел функций. Что это все <=и -?

И почему нет switchникаких аргументов?

&&должно означать и , но что 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
    }
}

Большинство из них из http://play.golang.org/p/H6wjLZj6lW

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

Я понимаю, что это сопоставление, runeчтобы stringон мог вернуть поменялся строкой. Но я не понимаю, как именно runeили byteработает здесь.

Квентин Гибсон
источник
Sidenote: Это не делает то, что молодые читатели могут захотеть сделать для английского слова «café» и других, не говоря уже о других языках. В Go есть библиотеки с достойной поддержкой действительно полезных вариантов такого преобразования.
RedGrittyBrick
2
В случае, если кто-то хочет знать, откуда появилось слово «руна»: en.wikipedia.org/wiki/Runic_(Unicode_block)
Мэтт Браун,
A []runeможет быть установлен в логический, числовой или строковый тип. См. Stackoverflow.com/a/62739051/12817546 .
Том Дж

Ответы:

149

Рунические литералы - это просто 32-битные целочисленные значения ( однако они являются нетипизированными константами, поэтому их тип может меняться ). Они представляют кодовые точки Unicode. Например, литерал руны 'a'- это на самом деле число 97.

Поэтому ваша программа в значительной степени эквивалентна:

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

Это должно быть очевидно, если вы посмотрите на отображение Unicode, которое идентично ASCII в этом диапазоне. Кроме того, 32 фактически является смещением между прописной и строчной кодовой точкой символа. Таким образом, добавляя 32к 'A', вы получаете 'a'и наоборот.

topskip
источник
12
Это, очевидно, работает только для символов ASCII, а не для символов со знаком ", например," ä ", не говоря уже о более сложных случаях, таких как" ı "(U + 0131). Go имеет специальные функции для отображения в нижний регистр, такие как unicode.ToLower(r rune) rune.
topskip
2
И добавить к правильному ответу @ topskip функцию SwapCase, которая работает для всех кодовых точек, а не только для az:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
ANisus
22
Руны являются значениями типа int32. Вот и весь ответ. Они не "сопоставлены" .
thwd
@AlixAxel: поведение SimpleFold практически одинаково (для большинства рун также используются ToLower и ToUpper). В некоторых случаях он отличается, например: DZ-> Dz, Dz-> dz, dz-> DZ. Мой SwapRune вместо этого будет идти: DZ-> dz, Dz-> DZ, dz-> DZ. Мне больше нравится ваше предложение :)
ANisus
3
Так руны похожи на символы?
Кенни Уорден
53

Из примечаний к выпуску Go lang: http://golang.org/doc/go1#rune

Руна - это Тип. Он занимает 32 бита и предназначен для представления Unicode CodePoint . В качестве аналогии набор английских символов, закодированный в «ASCII», имеет 128 кодовых точек. Таким образом, может поместиться внутри байта (8 бит). Из этого (ошибочного) предположения C рассматривал символы как «байты» char, а «строки» как «последовательность символов» char*.

Но угадайте что. Есть много других символов, изобретенных людьми, кроме символов «abcde ..». И их так много, что нам нужно 32 бит для их кодирования.

В Голанге тогда a stringявляется последовательностью bytes. Однако, поскольку несколько байтов могут представлять кодовую точку руны, строковое значение также может содержать руны. Таким образом, он может быть преобразован в []rune, или наоборот.

Пакет Unicode http://golang.org/pkg/unicode/ может дать представление о богатстве задачи.

fabrizioM
источник
6
В недавнем Unicode 6.3 определено более 110 000 символов. Это требует, по крайней мере, 21-битного представления каждой кодовой точки, так что a runeпохоже int32и имеет много битов.
Рик-777
2
Вы говорите: «это stringпоследовательность runeс» - я не думаю, что это правда? Перейти в блог : «строка - это просто набор байтов»; Go lang spec : «Строковое значение - это (возможно, пустая) последовательность байтов»
Крис Мартин,
1
Я все еще в замешательстве, так что строка это массив рун или массив байтов? Они взаимозаменяемы?
Гогофан
1
@prvn Это неправильно. Это как сказать, что изображение - это не последовательность байтов, а последовательность пикселей. Но на самом деле это серия байтов. Строка - это серия байтов, а не рун. Пожалуйста, прочитайте спецификацию .
Inanc Gumus
1
@prvn Но ты не можешь сказать not bytes. Тогда вы можете сказать: «Строки состоят из рун, а руны - из байтов». Что-то в этом роде. Затем снова. это не совсем так.
Inanc Gumus
28

Я старался, чтобы мой язык был простым, чтобы непрофессионал понимал rune.

Руна - это персонаж. Вот и все.

Это один персонаж. Это персонаж из любого алфавита с любого языка из любой точки мира.

Чтобы получить строку мы используем

double-quotes ""

ИЛИ

back-ticks ``

Строка отличается от руны. В рунах мы используем

single-quotes ''

Теперь руна также является псевдонимом для int32... А что?

Причина, по которой руна является псевдонимом, int32заключается в том, что мы видим, что в схемах кодирования, таких как ниже введите описание изображения здесь

каждый символ отображается на какое-то число, и это число, которое мы храним. Например, сопоставляется 97 и когда мы храним , что число это просто число и так , что это путь руна является псевдонимом для int32. Но это не просто число. Это число с 32 «нулями и единицами» или «4» байтами. (Примечание: UTF-8 является 4-байтовой схемой кодирования)

Как руны относятся к строкам?

Строка - это коллекция рун. В следующем коде:

    package main

    import (
        "fmt"
    )

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

Мы пытаемся преобразовать строку в поток байтов. Выход:

[72 101 108 108 111]

Мы можем видеть, что каждый из байтов, составляющих эту строку, является руной.

Сухай гупта
источник
2
A string is not a collection of runesстрого говоря, это не правильно. Вместо этого строка представляет собой байтовый фрагмент, закодированный с помощью utf8. Каждый символ в строке на самом деле занимает 1 ~ 3 байта, в то время как каждая руна занимает 4 байта. Вы можете конвертировать между строкой и [] рунами, но они разные.
Эрик Ван
2
Руна не символ, руна представляет кодовую точку Юникода. И кодовая точка не обязательно указывает на один символ.
Inanc Gumus
Стоит добавить, что «руна также является псевдонимом для int32» да, но это не значит, что она полезна для сжатия для бедняков ... Если вы нажмете что-то вроде 55296, преобразование строк сбивается: Go Playground
kubanczyk
27

Я не хватает репутации , чтобы добавить комментарий к fabrizioM в ответ , так что я должен разместить его здесь вместо этого.

Ответ Фабрицио в значительной степени правильный, и он, безусловно, уловил суть проблемы - хотя и следует провести различие.

Строка НЕ обязательно является последовательностью рун. Это обертка над «ломтиком байтов», причем обрезь является оберткой над массивом Go. Какая разница это делает?

Тип руны обязательно является 32-битным значением, то есть последовательность значений типов рун обязательно будет иметь некоторое количество битов x * 32. Строки, представляющие собой последовательность байтов, вместо этого имеют длину x * 8 бит. Если бы все строки были на самом деле в Юникоде, это различие не оказало бы никакого влияния. Так как строки представляют собой кусочки байтов , Go может использовать ASCII или любую другую произвольную байтовую кодировку.

Строковые литералы, однако, должны быть записаны в исходный код в UTF-8.

Источник информации: http://blog.golang.org/strings

Strangework
источник
1
Хорошая точка зрения ! Каждая руна требует 4 байта, но каждый символ в строке кодируется с utf8, таким образом, только 1 ~ 3 байта максимум.
Эрик Ван
16

(У меня сложилось впечатление, что приведенные выше ответы по-прежнему не отражают различия и отношения между ними stringи []runeочень четко, поэтому я постараюсь добавить еще один ответ с примером.)

Как @Strangeworkсказал ответ, stringи []runeтихо разные.

Отличия - string& []rune:

  • string valueявляется байтовым срезом только для чтения. И строковый литерал закодирован в utf-8. Каждый символ в stringдействительности занимает 1 ~ 3 байта, в то время как каждый runeзанимает 4 байта
  • Ибо string, len()и индекс основаны на байтах.
  • Ибо []rune, len()и индекс основаны на руне (или int32).

Отношения - string& []rune:

  • Когда вы конвертируете из stringв []rune, каждый символ utf-8 в этой строке становится rune.
  • Точно так же при обратном преобразовании, при преобразовании из []runeв string, каждый runeстановится символом utf-8 в string.

Подсказки:

  • Вы можете конвертировать между stringи []rune, но все же они разные, как по типу, так и по общему размеру.

(Я хотел бы добавить пример, чтобы показать это более четко.)


Код

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

Выполнение:

иди беги string_rune_compare.go

Вывод:

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

Объяснение:

  • Строка hello你好имеет длину 11, потому что первые 5 символов занимают по 1 байту, а последние 2 символа по 3 байта.

    • Таким образом, total bytes = 5 * 1 + 2 * 3 = 11
    • Поскольку len()строка основана на байтах, первая строка печатаетсяlen: 11
    • Поскольку индекс по строке также основан на байтах, таким образом, следующие 2 строки выводят значения типа uint8(так byteкак это псевдоним типа uint8в go).
  • Когда конвертировать stringв []rune, он нашел 7 utf8 символов, таким образом 7 рун.

    • Так как len()на []runeоснове руны, то последняя строка печатается len: 7.
    • Если вы работаете []runeчерез индекс, он получит доступ к базе на руне.
      Поскольку каждая руна взята из символа utf8 в исходной строке, вы также можете сказать, что len()и операция с индексами []runeоснованы на символах utf8.
Эрик Ван
источник
"Для строки оба len () и index основаны на байтах." Не могли бы вы объяснить это немного больше? Когда я это делаю, fmt.Println("hello你好"[0])он возвращает фактическую кодовую точку UTF-8 вместо байтов.
Джулиан
@Julian Пожалуйста, взгляните на вывод программы в ответе, потому что s[0]она печатает s[0]: 104, type: uint8, тип is uint8означает, что это байт. Для символов ASCII, таких как hutf-8, также используется один байт для его представления, поэтому кодовая точка совпадает с одним байтом; но для китайских символов, как , он использует 3 байта.
Эрик Ван
Уточняющий пример. Я процитировал вас здесь stackoverflow.com/a/62739051/12817546 .
Том Дж
7

Все остальные освещали часть, касающуюся рун, поэтому я не буду об этом говорить.

Тем не менее, есть также вопрос, связанный с switchотсутствием каких-либо аргументов. Это просто потому, что в Golang switchбез выражения есть альтернативный способ выражения логики if / else. Например, написать это:

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

так же, как писать это:

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

Вы можете прочитать больше здесь .

Шашанк Гоял
источник
0

Руна - это значение типа int32, и, следовательно, это тип Go, который используется для представления кодовой точки Unicode. Кодовая точка Unicode или позиция кода - это числовое значение, которое обычно используется для представления отдельных символов Unicode;

Remario
источник