Треки
/
Go
Go
/
Вправи
/
Логи, логи, логи!
Логи, логи, логи!

Логи, логи, логи!

Навчальна вправа

Вступ

Тип rune у Go - це псевдонім для int32. З огляду на цей базовий тип int32, тип rune зберігає знакове 32-бітне ціле значення. Однак, на відміну від типу int32, ціле значення, збережене в типі rune, представляє один символ Unicode.

Unicode і кодові точки Unicode

Unicode є надмножиною ASCII, яка представляє символи, призначаючи кожному символу унікальне число. Це унікальне число називається кодовою точкою Unicode. Unicode прагне представити всі символи світу, зокрема різні алфавіти, числа, символи й навіть емодзі, як кодові точки Unicode.

У Go тип rune представляє одну кодову точку Unicode.

Наступна таблиця містить приклади символів Unicode разом з їхніми кодовими точками Unicode та десятковими значеннями:

Символ Unicode Кодова точка Unicode Десяткове значення
0 U+0030 48
A U+0041 65
a U+0061 97
¿ U+00BF 191
π U+03C0 960
🧠 U+1F9E0 129504

UTF-8

UTF-8 - це кодування символів зі змінною шириною, яке використовується, щоб закодувати кожну кодову точку Unicode як 1, 2, 3 або 4 байти. Оскільки кодову точку Unicode можна закодувати щонайбільше 4 байтами, тип rune має бути здатним умістити до 4 байтів даних. Саме тому тип rune є псевдонімом для int32, адже тип int32 здатен умістити до 4 байтів даних.

Файли з вихідним кодом Go кодуються в UTF-8.

Використання rune

Змінні типу rune оголошуються, якщо помістити символ в одинарні лапки:

myRune := '¿'

Оскільки rune - це лише псевдонім для int32, виведення типу rune дасть int32:

myRune := '¿'
fmt.Printf("myRune type: %T\n", myRune)
// Output: myRune type: int32

Подібно до цього, виведення значення rune дасть його ціле (десяткове) значення:

myRune := '¿'
fmt.Printf("myRune value: %v\n", myRune)
// Output: myRune value: 191

Щоб вивести символ Unicode, який представляє rune, використаймо %c як дієслово форматування:

myRune := '¿'
fmt.Printf("myRune Unicode character: %c\n", myRune)
// Output: myRune Unicode character: ¿

Щоб вивести кодову точку Unicode, яку представляє rune, використаймо %U як дієслово форматування:

myRune := '¿'
fmt.Printf("myRune Unicode code point: %U\n", myRune)
// Output: myRune Unicode code point: U+00BF

Rune і рядки тексту

Рядки тексту (англ. string) у Go кодуються в UTF-8, а це означає, що вони містять символи Unicode. Символи в рядках тексту зберігаються й кодуються як 1, 2, 3 або 4 байти залежно від символу Unicode, який вони представляють.

У Go для представлення послідовностей використовуються зрізи, і ці зрізи можна перебирати за допомогою range. Коли ми перебираємо рядок тексту, Go перетворює його на послідовність rune, кожна з яких займає 4 байти (нагадаємо, тип rune - це псевдонім для int32!)

Навіть попри те, що рядок тексту - це лише зріз байтів, ключове слово range перебирає rune рядка, а не його байти.

У цьому прикладі змінна index представляє початковий індекс послідовності байтів поточної rune, а змінна char представляє поточну rune:

myString := "❗hello"
for index, char := range myString {
  fmt.Printf("Index: %d\tCharacter: %c\t\tCode Point: %U\n", index, char, char)
}
// Output:
// Index: 0	Character: ❗		Code Point: U+2757
// Index: 3	Character: h		Code Point: U+0068
// Index: 4	Character: e		Code Point: U+0065
// Index: 5	Character: l		Code Point: U+006C
// Index: 6	Character: l		Code Point: U+006C
// Index: 7	Character: o		Code Point: U+006F

Оскільки rune можуть зберігатися як 1, 2, 3 або 4 байти, довжина рядка тексту не завжди дорівнює кількості символів у ньому. Використаймо вбудовану функцію len, щоб отримати довжину рядка тексту в байтах, і функцію utf8.RuneCountInString, щоб отримати кількість rune у рядку тексту:

import "unicode/utf8"

myString := "❗hello"
stringLength := len(myString)
numberOfRunes := utf8.RuneCountInString(myString)

fmt.Printf("myString - Length: %d - Runes: %d\n", stringLength, numberOfRunes)
// Output: myString - Length: 8 - Runes: 6

Вказівки

Нам доручено створити бібліотеку для роботи з журналами, яка допоможе керувати журналами нашої організації. Ця бібліотека дасть змогу визначати, який застосунок створив відповідний журнал, виправляти пошкоджені журнали та зʼясовувати, чи вкладається рядок журналу в задану межу символів.

1. Визначити, який застосунок створив журнал

Журнали надходять від багатьох застосунків, кожен з яких використовує власний формат журналювання. Перед тим як зберегти журнал у системі агрегації журналів, потрібно визначити застосунок, який його створив.

Реалізуйте функцію Application, яка приймає рядок журналу й повертає застосунок, що створив цей рядок журналу.

Щоб визначити, який застосунок створив заданий рядок журналу, знайдіть у цьому рядку символ, указаний у наступній таблиці:

Застосунок Символ Кодова позиція Unicode
recommendation ❗ U+2757
search 🔍 U+1F50D
weather ☀ U+2600

Якщо рядок журналу не містить жодного символу з таблиці вище, поверніть default тому, хто викликав функцію. Якщо рядок журналу містить більше ніж один символ із таблиці вище, поверніть застосунок, що відповідає першому символу, знайденому в рядку журналу зліва направо.

Application("❗ recommended search product 🔍")
// => recommendation

2. Виправити пошкоджені журнали

Через рідкісний, але постійний bug в інфраструктурі журналювання деякі символи в журналах можуть пошкоджуватися. Присвятивши час визначенню пошкоджених символів та їхніх вихідних значень, ми вирішуємо оновити бібліотеку, щоб вона допомагала виправляти пошкоджені журнали.

Реалізуйте функцію Replace, яка приймає рядок журналу, пошкоджений символ і вихідне значення та повертає змінений рядок журналу, у якому всі входження пошкодженого символу замінено на вихідне значення.

log := "please replace '👎' with '👍'"

Replace(log, '👎', '👍')
// => please replace '👍' with '👍'"

3. Визначити, чи можна показати журнал

Системи, що відповідають за показ журналів, мають обмеження на кількість символів, які можна показати в одному рядку журналу. Тож користувачі просять додати до цієї бібліотеки допоміжну функцію, яка визначає, чи вкладається рядок журналу в задану межу символів.

Реалізуйте функцію WithinLimit, яка приймає рядок журналу й межу символів та повертає, чи вкладається рядок журналу в цю межу символів.

WithinLimit("hello❗", 6)
// => true
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Go Exercism

Час розпочати Логи, логи, логи!?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Go, а також 34 концепції165 вправ та справжнє наставництво від людей, і все це безкоштовно.