141 lines
6.3 KiB
Markdown
141 lines
6.3 KiB
Markdown
---
|
||
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)
|