UTF-8
Модератор: Olej
- Olej
- Писатель
- Сообщения: 18788
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
UTF-8
Известно, что UTF-8 - это способ кодирования символов в представлении Unicode.
Что в старых языках создаёт много проблем для локализованных не ASCII строк...
Например, в C (стардарты POSIX.1-2001, POSIX.1-2008, C99) строки в UTF-8 (multibyte characters) обрабатываются группой функций mb*() (mblen() и др.). А Unicode символы представляются типом wchar_t, и обюрабатываются функциями (аналогами str*() в ANSI C) вида wc*() (wcslen() и др.) + множеством функций осуществляющих взаимодействие и преобразования wchar_t и multibyte characters (типа mbsrtowcs(), mbrtowc() и др.) см.: wchar.h - wide-character handling.
В Linux (GCC) Unicode символы, wchar_t вседа имеют размер 4 байта, представление UTF-32 ... независимо что они там чудят в Windows (и в cygwin), с их представлением Unicode как UTF-16, см.: wchar_t string on Linux, OS X and Windows.
Это всё достаточно общеизвестные вещи + очень важно для локализованных программ (русских, китайских, хинди ... и мн. мн. другие) + то что вам нигде особенно подробно не напишут в англоязычнх переводных книгах.
Я об этих вещах ... по крайней мере, относительно "классики" - C/C++ - написал, в своё время, 2 статьи: Локализация и регулярные выражения, C/C++
... которые, в конечном итоге, слились в один общий текст...
Что в старых языках создаёт много проблем для локализованных не ASCII строк...
Например, в C (стардарты POSIX.1-2001, POSIX.1-2008, C99) строки в UTF-8 (multibyte characters) обрабатываются группой функций mb*() (mblen() и др.). А Unicode символы представляются типом wchar_t, и обюрабатываются функциями (аналогами str*() в ANSI C) вида wc*() (wcslen() и др.) + множеством функций осуществляющих взаимодействие и преобразования wchar_t и multibyte characters (типа mbsrtowcs(), mbrtowc() и др.) см.: wchar.h - wide-character handling.
В Linux (GCC) Unicode символы, wchar_t вседа имеют размер 4 байта, представление UTF-32 ... независимо что они там чудят в Windows (и в cygwin), с их представлением Unicode как UTF-16, см.: wchar_t string on Linux, OS X and Windows.
Это всё достаточно общеизвестные вещи + очень важно для локализованных программ (русских, китайских, хинди ... и мн. мн. другие) + то что вам нигде особенно подробно не напишут в англоязычнх переводных книгах.
Я об этих вещах ... по крайней мере, относительно "классики" - C/C++ - написал, в своё время, 2 статьи: Локализация и регулярные выражения, C/C++
... которые, в конечном итоге, слились в один общий текст...
- Olej
- Писатель
- Сообщения: 18788
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: UTF-8
Но вот в новых языках авторы сразу пошли на все символьные представления в UTF-8:
- Go: Go + Примеры кода Go + cборка приложений Go + GUI на Go Go : инструментарий (продолжение)
- Rust: Rust + код на Rust + Rust: новый подход к снаряду...
P.S. Да и Python в линейке версий 3.Х установлена дефаултная кодировка UTF-8
Теперь можно в заголовке кода Python не выписывать явно, что требовалось в версиях Python 2.X:
Код: Выделить всё
# -*- coding: utf-8 -*-
- Olej
- Писатель
- Сообщения: 18788
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: UTF-8
Но мне очень понравилось объяснение от авторов Rust - Байты, скалярные значения и кластеры графем! Боже мой!...
Настолько понравилось, что полностью скопирую это сюда:
Ещё один момент, касающийся UTF-8, заключается в том, что на самом деле существует три способа рассмотрения строк с точки зрения Rust: как байты, как скалярные значения и как кластеры графем (самая близкая вещь к тому, что мы назвали бы буквами).
Если посмотреть на слово языка хинди «नमस्ते», написанное в транскрипции Devanagari, то оно хранится как вектор значений u8 который выглядит следующим образом:
[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164,
224, 165, 135]
Эти 18 байт являются именно тем, как компьютеры в конечном итоге сохранят в памяти эту строку. Если мы посмотрим на 18 байт как на скалярные Unicode значения, которые являются Rust типом char, то байты будут выглядеть так:
['न', 'म', 'स', '्', 'त', 'े']
Здесь есть шесть значений типа char, но четвёртый и шестой являются не буквами: они диакритики, специальные обозначения которые не имеют смысла сами по себе. Наконец, если мы посмотрим на байты как на кластеры графем, то получим то, что человек назвал бы словом на хинди состоящем из четырёх букв:
["न", "म", "स्", "ते"]
Rust предоставляет различные способы интерпретации необработанных строковых данных, которые компьютеры хранят так, чтобы каждой программе можно было выбрать необходимую интерпретацию, независимо от того, на каком человеческом языке представлены эти данные.
Последняя причина, по которой Rust не позволяет нам индексировать String для получения символов является то, что программисты ожидают, что операции индексирования всегда имеют постоянное время (O(1)) выполнения. Но невозможно гарантировать такую производительность для String, потому что Rust понадобилось бы пройтись по содержимому от начала до индекса, чтобы определить, сколько было действительных символов.
- Olej
- Писатель
- Сообщения: 18788
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: UTF-8
Меня в этой связи заинтересовал вопрос проверить: насколько глубоко проникает UTF-8 в синтаксис языка?
Т.е. ... можно ли использовать локализованные символы Unicode только в содержимом текстовых литералов (строк) ... или, например, и в записи идентификаторов в коде?
В этой связи начал с Go ... про который априорно знаю что "можно"

Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ cat utf8go.go
package main
import "fmt"
func main() {
строка := "строка"
fmt.Printf("вывод: %s\n", строка)
안녕하세요 := "안녕하세요"
fmt.Printf("вывод: %s\n", 안녕하세요)
}

Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ go build -o utf8go utf8go.go
olej@R420:~/2022/Rust/utf-8$ ls -l utf8go
-rwxrwxr-x 1 olej olej 1796565 ноя 2 18:53 utf8go
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ ./utf8go
вывод: строка
вывод: 안녕하세요
- Вложения
-
utf8go.go
- (223 байт) 13 скачиваний
- Olej
- Писатель
- Сообщения: 18788
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: UTF-8
Дальше - Python ... где я, в значительной мере, предполагаю что будет:
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ cat utf8py.py
строка = "строка"
print("вывод: {}".format(строка))
안녕하세요 = "안녕하세요"
print("вывод: {}".format(안녕하세요))
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ python3 utf8py.py
вывод: строка
вывод: 안녕하세요

А вот Python 2:
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ python2 utf8py.py
File "utf8py.py", line 9
SyntaxError: Non-ASCII character '\xd1' in file utf8py.py on line 10, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
olej@R420:~/2022/Rust/utf-8$ python utf8py.py
File "utf8py.py", line 9
SyntaxError: Non-ASCII character '\xd1' in file utf8py.py on line 10, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
- Вложения
-
utf8py.py
- (161 байт) 14 скачиваний
- Olej
- Писатель
- Сообщения: 18788
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: UTF-8
Ну и, наконец, Rust с которого всё началось:
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ cat utf8rs.rs
fn main() {
let строка = "строка";
println!("вывод: {}", &строка);
let 안녕하세요 = "안녕하세요";
println!("вывод: {}", &안녕하세요);
}
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ rustc utf8rs.rs
warning: the usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables
--> utf8rs.rs:19:9
|
19 | let строка = "строка";
| ^^^^^^
|
= note: `#[warn(mixed_script_confusables)]` on by default
= note: the usage includes 'а' (U+0430), 'к' (U+043A), 'о' (U+043E), 'р' (U+0440), 'с' (U+0441), 'т' (U+0442)
= note: please recheck to make sure their usages are indeed what you want
warning: 1 warning emitted
1). это warning, но не error ...
2). исполнимый файл создан:
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$
ls -l utf8rs
-rwxrwxr-x 1 olej olej 3888344 ноя 2 19:30 utf8rs

4). почти наверняка это предупреждение можно удалить ... какими-нибудь прагмами, определениями ... но я пока не разбирался как.
Выполнение:
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ ./utf8rs
вывод: строка
вывод: 안녕하세요

- Вложения
-
utf8rs.rs
- (196 байт) 13 скачиваний
- Olej
- Писатель
- Сообщения: 18788
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: UTF-8
Лёгкий поиск приводит к обстоятельному описанию как: Allow non-ASCII letters (such as accented characters, Cyrillic, Greek, Kanji, etc.) in Rust identifiers.
Start Date: 2018-06-03
RFC PR: rust-lang/rfcs#2457
Но если поместить непосредственно в файл .rs : #[allow(confusable_idents)] ... то получите новое предупреждение:As an implementation note, it may be worth dealing with confusable modifiers via a separate lint check -- if a modifier is from a different (non-Common/Inherited) script group from the thing preceding it. This has some behavioral differences but should not increase the chance of false positives.
The exception for Latin is made because the standard library is Latin-script. It could potentially be removed since a code base using the standard library (or any Latin-using library) is likely to be using enough of it that there will be non-confusable characters in use. (This is in unresolved questions)
Код: Выделить всё
warning: allow(confusable_idents) is ignored unless specified at crate level
--> main.rs:2:9
|
2 | #[allow(confusable_idents)]
| ^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_attributes)]` on by default
И, в конечном, итоге:
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ cat utf8rs.rs
#![allow(mixed_script_confusables)]
fn main() {
let строка = "строка";
println!("вывод: {}", &строка);
let 안녕하세요 = "안녕하세요";
println!("вывод: {}", &안녕하세요);
}
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ rustc utf8rs.rs
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ ls -l utf8rs
-rwxrwxr-x 1 olej olej 3888344 ноя 2 20:07 utf8rs
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ ./utf8rs
вывод: строка
вывод: 안녕하세요

- Вложения
-
utf8rs.rs
- (233 байт) 13 скачиваний
- Olej
- Писатель
- Сообщения: 18788
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: UTF-8
И напоследок, пока, иллюстрация того как Rust работает с самыми разнообразными языками (которые никак соотносятся с locale которые установлены в системе!):
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ cat mullang.rs
fn greet_world() {
let regions = [
String::from("السلام عليكم"),
String::from("Dobrý den"),
String::from("Hello"),
String::from("שָׁלוֹם"),
String::from("नमस्ते"),
String::from("こんにちは"),
String::from("안녕하세요"),
String::from("你好"),
String::from("Olá"),
String::from("Здравствуйте"),
String::from("Hola"),
];
for region in regions.iter() {
println!("{}", ®ion);
}
}
fn main() {
greet_world();
}



Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ rustc mullang.rs
olej@R420:~/2022/Rust/utf-8$ ./mullang
السلام عليكم
Dobrý den
Hello
שָׁלוֹם
नमस्ते
こんにちは
안녕하세요
你好
Olá
Здравствуйте
Hola
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ rustc mullang.rs
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ ./mullang
السلام عليكم
Dobrý den
Hello
שָׁלוֹם
नमस्ते
こんにちは
안녕하세요
你好
Olá
Здравствуйте
Hola
- Вложения
-
mullang.rs
- (592 байт) 13 скачиваний
- Olej
- Писатель
- Сообщения: 18788
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: UTF-8
Ну и окончательно, о том как представляется Rust строка в символах и в байтах ...
Байты, скалярные значения и кластеры графем! Боже мой!
Длина строки в символах и байтах, что и понятно, различаются.
Байты, скалярные значения и кластеры графем! Боже мой!
Ещё один момент, касающийся UTF-8, заключается в том, что на самом деле существует три способа рассмотрения строк с точки зрения Rust: как байты, как скалярные значения и как кластеры графем (самая близкая вещь к тому, что мы назвали бы буквами).
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ cat loopch.rs
fn main() {
let string = "Привет".to_string();
for c in string.chars() {
println!("{}", c);
}
for b in string.bytes() {
println!("{}", b);
}
}
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ rustc loopch.rs
Код: Выделить всё
olej@R420:~/2022/Rust/utf-8$ ./loopch
П
р
и
в
е
т
208
159
209
128
208
184
208
178
208
181
209
130
- Вложения
-
loopch.rs
- (187 байт) 13 скачиваний
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость