Files
obsidian/Kotlin/Синтаксис и типы/Работа с данными/Char.md
T

141 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Char
description: Char как отдельный тип, код символа, проверки категорий и работа с цифрами
tags:
- kotlin
- stdlib
---
`Char` - один символ в одинарных кавычках. Хранит кодовую единицу UTF-16 (16 бит).
```kotlin
val c: Char = 'A'
val tab = '\t'
val quote = '\''
val unicode = '\u00A9' // ©
```
Ключевое отличие от Java: **`Char` не является числом**. Арифметику с ним делать можно, но неявного превращения в `Int` нет.
```kotlin
val c = 'A'
// val n: Int = c // ошибка компиляции
val n: Int = c.code // 65 — явно
println(c + 1) // B — Char + Int = Char
println('z' - 'a') // 25 — Char - Char = Int
println(c.toString()) // A
```
| Выражение | Результат | Тип |
|---|---|---|
| `'A' + 1` | `'B'` | `Char` |
| `'z' - 'a'` | `25` | `Int` |
| `'A'.code` | `65` | `Int` |
| `65.toChar()` | `'A'` | `Char` |
## Проверки категорий
```kotlin
println('a'.isLetter()) // true
println('5'.isDigit()) // true
println('a'.isLetterOrDigit()) // true
println(' '.isWhitespace()) // true
println('a'.isLowerCase()) // true
println('A'.isUpperCase()) // true
```
Все эти функции учитывают Unicode: `'я'.isLetter()` тоже `true`.
## Регистр
```kotlin
println('a'.uppercaseChar()) // A — возвращает Char
println('A'.lowercaseChar()) // a
println('a'.uppercase()) // "A" — возвращает String
println('ß'.uppercase()) // "SS" — два символа, поэтому String
```
Есть две версии: `uppercaseChar()` даёт `Char`, `uppercase()` - `String`. Вторая нужна, потому что в Unicode регистр не всегда меняется один-к-одному.
## Цифры
```kotlin
println('7'.digitToInt()) // 7 — число, а не код символа
println('f'.digitToInt(16)) // 15
println('x'.digitToIntOrNull()) // null — безопасная версия
println(7.digitToChar()) // '7'
```
Это главный способ разобрать цифру. Старый трюк из Java (`c - '0'`) тоже работает, но `digitToInt()` понятнее и проверяет корректность:
```kotlin
println('7' - '0') // 7 — работает
// println('x'.digitToInt()) // IllegalArgumentException
```
## Диапазоны и сравнение
```kotlin
println('a' in 'a'..'z') // true
println('5' in '0'..'9') // true
for (c in 'a'..'e') print(c) // abcde
println('a' < 'b') // true — по коду
println(('a'..'e').toList()) // [a, b, c, d, e]
```
## Строки и Char
```kotlin
val s = "Kotlin"
println(s[0]) // K — элемент строки это Char
println(s.first()) // K
println(s.toCharArray().size) // 6
println(String(charArrayOf('a','b'))) // ab — собрать строку из массива
println(s.toList()) // [K, o, t, l, i, n]
println("abc".map { it + 1 }) // [b, c, d]
println(charArrayOf('a','b').concatToString()) // ab
```
Приписать `Char` к строке можно сложением - слева обязательно строка:
```kotlin
println("ab" + 'c') // abc
// println('c' + "ab") // ошибка: Char.plus ожидает Int
println("${'c'}ab") // cab — через шаблон
```
> [!info] Отличия от Java
> | Java | Kotlin |
> |---|---|
> | `char` - числовой тип | `Char` - отдельный тип |
> | `int n = c;` работает | нужен `c.code` |
> | `Character.isDigit(c)` | `c.isDigit()` |
> | `Character.toUpperCase(c)` | `c.uppercaseChar()` |
> | `Character.getNumericValue(c)` | `c.digitToInt()` |
> | `c - '0'` для цифры | `c.digitToInt()` |
> | `switch (c)` по числам | `when (c)` по символам |
>
> В Java `char` участвует в арифметике как число, из-за чего `System.out.println('a' + 1)` печатает `98`, а не `b`. В Kotlin тот же код даёт `b` - тип сохраняется.
>
> Все утилиты из `Character` стали методами `Char`, поэтому пишутся через точку и находятся автодополнением.
>
> Сравнить: [Character в Java](../../../Программирование%20на%20Java/Синтаксис%20и%20типы/Работа%20с%20данными%20и%20типами/Character.md)
> [!warning] Подводные камни
> **`Char` не вмещает символы за пределами BMP.** Эмодзи и редкие иероглифы кодируются двумя `Char` (surrogate pair):
> ```kotlin
> val emoji = "😀"
> println(emoji.length) // 2
> println(emoji[0].isLetter()) // false — половина пары бессмысленна
> println(emoji.codePointAt(0)) // 128512 — полный код символа
> ```
> Для посимвольной обработки текста с эмодзи нужны кодовые точки, а не `Char`.
>
> **`digitToInt()` бросает исключение, а не возвращает -1:**
> ```kotlin
> println('x'.digitToIntOrNull()) // null — безопасно
> // println('x'.digitToInt()) // IllegalArgumentException
> ```
>
> **`'1'.code` - это 49, а не 1.** Путать код символа с его числовым значением - классическая ошибка:
> ```kotlin
> println('1'.code) // 49
> println('1'.digitToInt()) // 1
> ```
>
> **`Char` в `when` требует `else`** - перечислить все 65 536 значений компилятор не может.
>
> **`uppercase()` возвращает `String`, и это не придирка.** `'ß'.uppercase()` даёт `"SS"` - два символа. Если нужен именно `Char`, используйте `uppercaseChar()`, но помните, что для `'ß'` он вернёт сам `'ß'`.
Далее: [Числа и переполнение](Числа%20и%20переполнение.md)