Сравнение символов и практический пример


1. Основа: символы — это числа

Строка = набор байт
Байты = числа
Числа можно сравнивать

char := 'A'
fmt.Printf("'A' = %d\n", char)  // 65 (Unicode code point)

Руна (символ) — это int32, поэтому поддерживает все операции сравнения.


2. Сравнение символов

char := 'M'

if char >= 'A' && char <= 'Z' {
    fmt.Println("Заглавная латинская буква")
}

if char >= 'a' && char <= 'z' {
    fmt.Println("Строчная латинская буква")
}

Работает: Сравниваем коды Unicode.


3. Диапазоны символов

Диапазон Символы Коды
'A'...'Z' Заглавные латинские 65–90
'a'...'z' Строчные латинские 97–122
'А'...'Я' Заглавные кириллические 1040–1071
'а'...'я' Строчные кириллические 1072–1103
'0'...'9' Цифры 48–57

4. Практический пример: подсчёт букв

sentence := "ёHello, мир! 🌍"

fmt.Printf("Предложение: %s\n", sentence)
fmt.Printf("len(): %d байт\n", len(sentence))
fmt.Printf("Символов: %d\n", utf8.RuneCountInString(sentence))

Вывод:

Предложение: ёHello, мир! 🌍
len(): 26 байт
Символов: 14

5. Подсчёт букв

letterCount := 0

for _, char := range sentence {
    if (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') ||
       (char >= 'а' && char <= 'я') || (char >= 'А' && char <= 'Я') {
        letterCount++
    }
}

fmt.Printf("Букв: %d\n", letterCount)

Вывод:

Букв: 10

Подсчитаны: H, e, l, l, o, м, и, р — латиница и кириллица.


6. ⚠️ Проблема: неполное условие

Что не учтено?

if (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') ||
   (char >= 'а' && char <= 'я') || (char >= 'А' && char <= 'Я')

Не учитывается:

  • 'ё' и 'Ё'вне диапазона 'а'...'я'
  • Другие кириллические буквы: 'ї', 'є', 'і' (украинские)
  • Акцентированные символы: 'é', 'ñ', 'ü'

Полный пример с 'ё'

sentence := "ёHello"

// ❌ Не найдёт 'ё'
letterCount := 0
for _, char := range sentence {
    if (char >= 'а' && char <= 'я') || (char >= 'А' && char <= 'Я') {
        letterCount++
    }
}
fmt.Println(letterCount)  // 0 (ё не в диапазоне!)

Проблема: 'ё' (код 1105) больше 'я' (код 1103).


7. Правильное решение: проверка 'ё' и 'Ё'

letterCount := 0

for _, char := range sentence {
    if (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') ||
       (char >= 'а' && char <= 'я') || (char >= 'А' && char <= 'Я') ||
       char == 'ё' || char == 'Ё' {  // ✅ Добавлено
        letterCount++
    }
}

fmt.Printf("Букв: %d\n", letterCount)

Теперь: 'ё' учитывается.


8. Универсальное решение: unicode.IsLetter()

import "unicode"

letterCount := 0

for _, char := range sentence {
    if unicode.IsLetter(char) {
        letterCount++
    }
}

fmt.Printf("Букв: %d\n", letterCount)

Преимущества:

  • Работает для любых алфавитов (греческий, арабский, китайский)
  • Учитывает все буквы Unicode
  • Не нужно знать диапазоны

9. Другие полезные функции unicode

import "unicode"

char := 'A'

unicode.IsLetter(char)  // true — буква
unicode.IsDigit(char)   // false — цифра
unicode.IsSpace(char)   // false — пробельный символ
unicode.IsUpper(char)   // true — заглавная
unicode.IsLower(char)   // false — строчная
unicode.ToUpper(char)   // 'A' — в верхний регистр
unicode.ToLower(char)   // 'a' — в нижний регистр

10. Сравнение подходов

Подход Плюсы Минусы
Диапазоны 'a'...'z' Быстро, явно Не учитывает 'ё', акценты
unicode.IsLetter() Универсально Немного медленнее

11. Практические примеры

Проверка пароля (только буквы и цифры)

import "unicode"

func isValidPassword(password string) bool {
    for _, char := range password {
        if !unicode.IsLetter(char) && !unicode.IsDigit(char) {
            return false
        }
    }
    return true
}

fmt.Println(isValidPassword("Pass123"))   // true
fmt.Println(isValidPassword("Pass-123"))  // false (дефис)

Подсчёт типов символов

text := "Hello, мир! 123"

letters, digits, spaces := 0, 0, 0

for _, char := range text {
    switch {
    case unicode.IsLetter(char):
        letters++
    case unicode.IsDigit(char):
        digits++
    case unicode.IsSpace(char):
        spaces++
    }
}

fmt.Printf("Букв: %d, Цифр: %d, Пробелов: %d\n", letters, digits, spaces)
// Букв: 8, Цифр: 3, Пробелов: 2

Извлечение только букв

text := "Hello, мир! 123"
var result []rune

for _, char := range text {
    if unicode.IsLetter(char) {
        result = append(result, char)
    }
}

fmt.Println(string(result))  // "Helloмир"

12. Коды символов 'ё'

fmt.Printf("'а' = %d\n", 'а')  // 1072
fmt.Printf("'я' = %d\n", 'я')  // 1103
fmt.Printf("'ё' = %d\n", 'ё')  // 1105 — ВНЕ диапазона!
fmt.Printf("'Ё' = %d\n", 'Ё')  // 1025

Проблема: 'ё' (1105) > 'я' (1103), поэтому не попадает в 'а'...'я'.


13. Итоги

Руны (символы) можно сравнивать как числа
✅ Диапазоны: 'A'...'Z', 'a'...'z', 'а'...'я', 'А'...'Я'
⚠️ 'ё' и 'Ё' не входят в диапазон 'а'...'я'
✅ Для полноты добавляйте char == 'ё' || char == 'Ё'
unicode.IsLetter() — универсальное решение
unicode пакет: IsDigit, IsSpace, IsUpper, ToLower
✅ Сравнение работает через Unicode code points

Ключевое правило:

// ❌ Неполное (пропускает 'ё')
if char >= 'а' && char <= 'я' { ... }

// ✅ Полное (вручную)
if (char >= 'а' && char <= 'я') || char == 'ё' { ... }

// ✅ Универсальное
if unicode.IsLetter(char) { ... }

Практическая рекомендация:

import "unicode"

// Для любых алфавитов
for _, char := range text {
    if unicode.IsLetter(char) {
        // Обработка буквы
    }
}