Що таке руна?


188

Що таке " 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)
Метт Браун

А []runeможе бути встановлено як булевий, числовий чи рядковий тип. Дивіться stackoverflow.com/a/62739051/12817546 .
Том J

Відповіді:


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'і навпаки.


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
Отже, руни схожі на C chars?
Kenny Worden

53

З приміток до випуску Go lang: http://golang.org/doc/go1#rune

Руна - це тип. Він займає 32 біт і призначений для представлення Unicode CodePoint . Як аналогія, набір англійських символів, закодований у "ASCII", має 128 кодових точок. Таким чином, здатний поміститися всередині байта (8 біт). З цього (помилкового) припущення C трактуються символи як "байти" char, а "рядки" як "послідовність символів" char*.

Але вгадайте, що. Є багато інших символів, винайдених людьми, крім символів "abcde ..". І їх так багато, що для кодування нам потрібно 32 біт.

У голанг тоді а string- це послідовність bytes. Однак, оскільки кілька байтів можуть представляти кодову точку руни, значення рядка також може містити руни. Отже, він може бути перетворений в a []rune, або навпаки.

Пакет unicode http://golang.org/pkg/unicode/ може покуштувати насиченість проблеми.


6
З останнім Unicode 6.3 визначено понад 110 000 символів. Для цього потрібно щонайменше 21-бітове представлення кожної кодової точки, тому a runeє як int32і має багато бітів.
Рік-777

2
Ви кажете "a string- це послідовність runes" - я не думаю, що це правда? Перейти до блогу : "рядок - це лише купа байтів"; Перейти до специфікації : "Значення рядка - це (можливо, порожня) послідовність байтів"
Кріс Мартін

1
Я все ще плутаюсь, так це рядковий масив рун чи масив байтів? Вони взаємозамінні?
gogofan

1
@prvn Це неправильно. Це як би сказати, що зображення - це не послідовність байтів, це послідовність пікселів. Але насправді під ним - це ряд байтів. Рядок - це ряд байтів, а не рун. Будь ласка, прочитайте специфікацію .
Інанк Gumus

1
@prvn Але ви не можете сказати not bytes. Тоді ви можете сказати: "Струни складаються з рун і рун, що складаються з байтів" Щось подібне. Потім знову. це не зовсім правда.
Інанк 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, конверсія рядків збивається з
ладу

27

Я не вистачає репутації , щоб додати коментар до fabrizioM в відповідь , так що я повинен розмістити його тут замість цього.

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

Рядок НЕ обов'язково є послідовністю рун. Це обгортка над "шматочком байтів", фрагмент - обгорткою над масивом Go. Яка різниця в цьому?

Руна типу обов'язково є 32-бітове значення, тобто послідовність значень типів руна обов'язково мати деяке число бітів х * 32. Рядки, що є послідовністю байтів, натомість мають довжину x * 8 біт. Якби всі рядки були насправді в Unicode, ця різниця не мала б впливу. Оскільки рядки є фрагментами байтів , Go може використовувати ASCII або будь-яке інше довільне кодування байтів.

Однак рядкові літерали потрібно записати у джерело, закодоване в UTF-8.

Джерело інформації: http://blog.golang.org/strings


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
    • Оскільки індекс на рядку також базується на байтах, таким чином, наступні два рядки друкують значення типу uint8(оскільки byteце псевдонім типу uint8, в ходу).
  • Коли конвертувати stringв []rune, він знайшов 7 utf8 символів, таким чином 7 рун.

    • Оскільки len()на []runeоснові базується на руні, таким чином друкується останній рядок len: 7.
    • Якщо ви працюєте []runeчерез індекс, він отримає доступ до бази на руні.
      Оскільки кожна руна складається з знака utf8 в початковій строці, тож ви можете також сказати, що обидві len()і операції з індексом []runeзасновані на utf8 знаках.

"Для рядка і len (), і індекс базуються на байтах." Чи можете ви пояснити це ще трохи? Коли я fmt.Println("hello你好"[0])це роблю, він повертає фактичну точку коду UTF-8 замість байтів.
Джуліан

@Julian Будь ласка, подивіться на вихід програми у відповідь, бо s[0], вона друкує s[0]: 104, type: uint8, тип є uint8, означає її байт. Для ASCII символів, таких як hutf-8, також використовується один байт для його представлення, тому точка коду така ж, як і один байт; але для китайських символів він використовує 3 байти.
Ерік Ван

Уточнюючий приклад. Я цитував вас тут stackoverflow.com/a/62739051/12817546 .
Том J

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;

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.