Низове, utf-8, итерация
17 октомври 2024
Преговор
Преговор
- Структури (асоциирани функции, методи)
Преговор
- Структури (асоциирани функции, методи)
self
,&self
,&mut self
Преговор
- Структури (асоциирани функции, методи)
self
,&self
,&mut self
- enums
- варианти с данни
- екслузивност - или един пакет данни, или друг
Преговор
- Структури (асоциирани функции, методи)
self
,&self
,&mut self
- enums
- варианти с данни
- екслузивност - или един пакет данни, или друг
match
Преговор
- Структури (асоциирани функции, методи)
self
,&self
,&mut self
- enums
- варианти с данни
- екслузивност - или един пакет данни, или друг
match
- pattern matching / destructuring
Административни неща
Саит на курса: https://fmi.rust-lang.bg
Закодиране на низове
Закодиране на низове
ASCII
Закодиране на низове
ASCII
- един от по-ранните стандарти за кодиране
Закодиране на низове
ASCII
- един от по-ранните стандарти за кодиране
- 128 символа, кодирани с числа от 0 до 127
- 32 контролни символа
- 96 - латинската азбука, арабските цифри и най-често използваната пунктуация
Закодиране на низове
ASCII
- един от по-ранните стандарти за кодиране
- 128 символа, кодирани с числа от 0 до 127
- 32 контролни символа
- 96 - латинската азбука, арабските цифри и най-често използваната пунктуация
- недостатък - много ограничен набор от символи
Закодиране на низове
Кодови таблици
Закодиране на низове
Кодови таблици
- разширение на ASCII
Закодиране на низове
Кодови таблици
- разширение на ASCII
- 256 символа, кодирани с числа от 0 до 255
- 0 до 127 - ascii
- 128 до 255 - други символи (зависи от таблицата)
Закодиране на низове
Кодови таблици
- разширение на ASCII
- 256 символа, кодирани с числа от 0 до 255
- 0 до 127 - ascii
- 128 до 255 - други символи (зависи от таблицата)
- появили са се много (стотици) разширени таблици с кодове за различни случаи
Закодиране на низове
Кодови таблици
- разширение на ASCII
- 256 символа, кодирани с числа от 0 до 255
- 0 до 127 - ascii
- 128 до 255 - други символи (зависи от таблицата)
- появили са се много (стотици) разширени таблици с кодове за различни случаи
- например: latin-1, windows-1251, cp437, …
Закодиране на низове
Кодови таблици
Недостатъци:
Закодиране на низове
Кодови таблици
Недостатъци:
- много ограничен набор от символи в една таблица - трябва да се използват различни таблици
Закодиране на низове
Кодови таблици
Недостатъци:
- много ограничен набор от символи в една таблица - трябва да се използват различни таблици
- ако не знаем с коя таблица е кодиран низа, не знаем какви символи съдържа
Закодиране на низове
Кодови таблици
Недостатъци:
- много ограничен набор от символи в една таблица - трябва да се използват различни таблици
- ако не знаем с коя таблица е кодиран низа, не знаем какви символи съдържа
- никой не казва с коя таблица е кодиран низа
Закодиране на низове
Unicode
Закодиране на низове
Unicode
- стандарт, създаден да оправи цялата тази бъркотия
Закодиране на низове
Unicode
- стандарт, създаден да оправи цялата тази бъркотия
- голяма таблица която съдържа всички символи
Закодиране на низове
Unicode
- стандарт, създаден да оправи цялата тази бъркотия
- голяма таблица която съдържа всички символи
- дефинира съответствие от число (code point) до символ
Закодиране на низове
Unicode
- стандарт, създаден да оправи цялата тази бъркотия
- голяма таблица която съдържа всички символи
- дефинира съответствие от число (code point) до символ
- ℕ → символ
Закодиране на низове
Unicode
- стандарт, създаден да оправи цялата тази бъркотия
- голяма таблица която съдържа всички символи
- дефинира съответствие от число (code point) до символ
- ℕ → символ
- не дефинира как да се кодира числото (code point-а) като битове
Закодиране на низове
Chars
- типа
char
в Rust означава "unicode scalar value"
Закодиране на низове
Chars
- типа
char
в Rust означава "unicode scalar value" - (което е като "code point", но по-различно :)
- "Any Unicode code point except high-surrogate and low-surrogate code points. In other words, the ranges of integers 0 to D7FF16 and E00016 to 10FFFF16 inclusive")
Закодиране на низове
Chars
- пример:
Code: U+044F
Glyph: я
Description: Cyrillic Small Letter Ya
1
2
3
println!("{:#x}", 'я' as u32);
println!("{:?}", std::char::from_u32(0x044f));
0x44f Some('я')
fn main() { println!("{:#x}", 'я' as u32); println!("{:?}", std::char::from_u32(0x044f)); }
Закодиране на низове
UTF-32
- всеки символ се кодира с 32-битово число - стойността на code point-а
Закодиране на низове
UTF-32
- всеки символ се кодира с 32-битово число - стойността на code point-а
- все едно
Vec<char>
Закодиране на низове
UTF-16
Закодиране на низове
UTF-16
- всеки символ се кодира с едно или две 16-битови числа
Закодиране на низове
UTF-16
- всеки символ се кодира с едно или две 16-битови числа
- използва се в Windows API-та
Закодиране на низове
UTF-16
- всеки символ се кодира с едно или две 16-битови числа
- използва се в Windows API-та
- и за вътрешна репрезентация на низове в някои езици (напр. Java, JavaScript)
Закодиране на низове
UTF-8
Закодиране на низове
UTF-8
- символите се кодират с 1, 2, 3 или 4 байта
Закодиране на низове
UTF-8
- символите се кодират с 1, 2, 3 или 4 байта
- най-разпространения метод за кодиране
Закодиране на низове
UTF-8
- символите се кодират с 1, 2, 3 или 4 байта
- най-разпространения метод за кодиране
- низовете в Rust (
&str
,String
) са utf-8
Закодиране на низове
UTF-8
Схема на кодирането
Брой байтове | Първи code point | Последен code point | Байт 1 | Байт 2 | Байт 3 | Байт 4 |
---|---|---|---|---|---|---|
1 | U+0000 | U+007F | 0xxxxxxx | |||
2 | U+0080 | U+07FF | 110xxxxx | 10xxxxxx | ||
3 | U+0800 | U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |
4 | U+10000 | U+10FFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
Закодиране на низове
UTF-8
Пример: 한
(U+d55c)
Unicode code point bits:
11010101 01011100
UTF-8 bits:
11101101 10010101 10011100
Закодиране на низове
UTF-8
Пример: 💣
(U+1f4a3)
Unicode code point bits:
00000001 11110100 10100011
UTF-8 bits:
11110000 10011111 10010010 10100011
Закодиране на низове
UTF-8
Предимства:
Закодиране на низове
UTF-8
Предимства:
- съвместим с ASCII
Закодиране на низове
UTF-8
Предимства:
- съвместим с ASCII
- всеки ASCII низ е и utf-8 низ
Закодиране на низове
UTF-8
Предимства:
- съвместим с ASCII
- всеки ASCII низ е и utf-8 низ
- не-ASCII символите не съдържат ASCII байтове (0x00 - 0x7f)
Закодиране на низове
UTF-8
Предимства:
- съвместим с ASCII
- всеки ASCII низ е и utf-8 низ
- не-ASCII символите не съдържат ASCII байтове (0x00 - 0x7f)
- с две думи - код който очаква да работи с ASCII низ би приел utf-8 низ подобаващо
Закодиране на низове
UTF-8
Предимства:
- съвместим с ASCII
- всеки ASCII низ е и utf-8 низ
- не-ASCII символите не съдържат ASCII байтове (0x00 - 0x7f)
- с две думи - код който очаква да работи с ASCII низ би приел utf-8 низ подобаващо
- поток от байтове - няма значение от endianness
Закодиране на низове
UTF-8
Предимства:
- съвместим с ASCII
- всеки ASCII низ е и utf-8 низ
- не-ASCII символите не съдържат ASCII байтове (0x00 - 0x7f)
- с две думи - код който очаква да работи с ASCII низ би приел utf-8 низ подобаващо
- поток от байтове - няма значение от endianness
- устойчив на повреда на данните
Закодиране на низове
UTF-8
Предимства:
- съвместим с ASCII
- всеки ASCII низ е и utf-8 низ
- не-ASCII символите не съдържат ASCII байтове (0x00 - 0x7f)
- с две думи - код който очаква да работи с ASCII низ би приел utf-8 низ подобаващо
- поток от байтове - няма значение от endianness
- устойчив на повреда на данните
- и други
Закодиране на низове
UTF-8
Недостатъци:
- variable lenght encoding - преброяването на символите или намирането на n-тия символ изисква итерация по низа
Низове
Дължина
str::len()
връща дължината на низ в брой байтове
1
2
3
4
let hi = "Здравей! 😊";
println!("{}", hi.len());
println!("{}", hi.chars().count());
20 10
fn main() { let hi = "Здравей! 😊"; println!("{}", hi.len()); println!("{}", hi.chars().count()); }
Низове
Индексация
При взимане на резен от низ се оказват брой байтове
1
2
let sub_hi = &"Здравей! 😊"[0..6];
println!("{:?}", sub_hi);
"Здр"
fn main() { let sub_hi = &"Здравей! 😊"[0..6]; println!("{:?}", sub_hi); }
1
2
let sub_hi = &"Здравей! 😊"[0..3];
println!("{:?}", sub_hi);
thread 'main' panicked at src/bin/main_2c3c4f5929c61b0516fdd13c207f4dee42a64790.rs:2:28: byte index 3 is not a char boundary; it is inside 'д' (bytes 2..4) of `Здравей! 😊` note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
fn main() { let sub_hi = &"Здравей! 😊"[0..3]; println!("{:?}", sub_hi); }
Низове
Итерация
1
2
3
for c in "Здравей! 😊" {
// ...
}
error[E0277]: `&str` is not an iterator --> src/bin/main_d4d96cd45194a2a7f7b2fdd29a913a03c9c66432.rs:2:10 | 2 | for c in "Здравей! 😊" { | ^^^^^^^^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` | = help: the trait `Iterator` is not implemented for `&str`, which is required by `&str: IntoIterator` = note: required for `&str` to implement `IntoIterator` For more information about this error, try `rustc --explain E0277`. error: could not compile `rust` (bin "main_d4d96cd45194a2a7f7b2fdd29a913a03c9c66432") due to 1 previous error
fn main() { for c in "Здравей! 😊" { // ... } }
Низове
Итерация
1
2
3
for b in "Здравей! 😊".bytes() {
print!("{:02x} ", b);
}
d0 97 d0 b4 d1 80 d0 b0 d0 b2 d0 b5 d0 b9 21 20 f0 9f 98 8a
fn main() { for b in "Здравей! 😊".bytes() { print!("{:02x} ", b); } println!(); }
Низове
Итерация
1
2
3
4
5
6
for c in "Здравей! 😊".chars() {
let char_string: String = c.to_string();
let char_utf8 = char_string.as_bytes();
println!("{}: code_point={:#x}, utf8={:x?}", c, c as u32, char_utf8);
}
З: code_point=0x417, utf8=[d0, 97] д: code_point=0x434, utf8=[d0, b4] р: code_point=0x440, utf8=[d1, 80] а: code_point=0x430, utf8=[d0, b0] в: code_point=0x432, utf8=[d0, b2] е: code_point=0x435, utf8=[d0, b5] й: code_point=0x439, utf8=[d0, b9] !: code_point=0x21, utf8=[21] : code_point=0x20, utf8=[20] 😊: code_point=0x1f60a, utf8=[f0, 9f, 98, 8a]
fn main() { for c in "Здравей! 😊".chars() { let char_string: String = c.to_string(); let char_utf8 = char_string.as_bytes(); println!("{}: code_point={:#x}, utf8={:x?}", c, c as u32, char_utf8); } }
Низове
Итерация
1
2
3
4
5
6
7
8
9
10
// аs_bytes() преобразува &str в &[u8]
println!("{:x?}", "Здравей! 😊".as_bytes());
// bytes() връща итератор по байтовете на низа
let bytes: Vec<u8> = "Здравей! 😊".bytes().collect();
println!("{:x?}", bytes);
// chars() връща итератор по символите в низа
let chars: Vec<char> = "Здравей! 😊".chars().collect();
println!("{:?}", chars);
[d0, 97, d0, b4, d1, 80, d0, b0, d0, b2, d0, b5, d0, b9, 21, 20, f0, 9f, 98, 8a] [d0, 97, d0, b4, d1, 80, d0, b0, d0, b2, d0, b5, d0, b9, 21, 20, f0, 9f, 98, 8a] ['З', 'д', 'р', 'а', 'в', 'е', 'й', '!', ' ', '😊']
fn main() { // аs_bytes() преобразува &str в &[u8] println!("{:x?}", "Здравей! 😊".as_bytes()); // bytes() връща итератор по байтовете на низа let bytes: Vec= "Здравей! 😊".bytes().collect(); println!("{:x?}", bytes); // chars() връща итератор по символите в низа let chars: Vec = "Здравей! 😊".chars().collect(); println!("{:?}", chars); }
Итерация
1
2
3
let numbers = [1, 2, 3].iter(); // std::slice::Iter
let chars = "abc".chars(); // std::str::Chars
let words = "one two three".split_whitespace(); // std::str::SplitWhitespace
Итерация
1
2
3
4
5
6
7
let numbers = [1, 2, 3].iter(); // std::slice::Iter
let chars = "abc".chars(); // std::str::Chars
let words = "one two three".split_whitespace(); // std::str::SplitWhitespace
println!("{:?}", numbers);
println!("{:?}", chars);
println!("{:?}", words);
Iter([1, 2, 3]) Chars(['a', 'b', 'c']) SplitWhitespace { inner: Filter { iter: Split(SplitInternal { start: 0, end: 13, matcher: CharPredicateSearcher { haystack: "one two three", char_indices: CharIndices { front_offset: 0, iter: Chars(['o', 'n', 'e', ' ', 't', 'w', 'o', ' ', 't', 'h', 'r', 'e', 'e']) } }, allow_trailing_empty: true, finished: false }) } }
fn main() { let numbers = [1, 2, 3].iter(); // std::slice::Iter let chars = "abc".chars(); // std::str::Chars let words = "one two three".split_whitespace(); // std::str::SplitWhitespace println!("{:?}", numbers); println!("{:?}", chars); println!("{:?}", words); }
Итерация
1
2
3
4
5
6
7
let numbers: Vec<&u32> = [1, 2, 3].iter().collect();
let chars: Vec<char> = "abc".chars().collect();
let words: Vec<&str> = "one two three".split_whitespace().collect();
println!("{:?}", numbers);
println!("{:?}", chars);
println!("{:?}", words);
[1, 2, 3] ['a', 'b', 'c'] ["one", "two", "three"]
fn main() { let numbers: Vec<&u32> = [1, 2, 3].iter().collect(); let chars: Vec= "abc".chars().collect(); let words: Vec<&str> = "one two three".split_whitespace().collect(); println!("{:?}", numbers); println!("{:?}", chars); println!("{:?}", words); }
Итерация
1
2
3
4
5
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
Итерация
1
2
3
let string = String::from("abc");
let chars = string.chars(); // std::str::Chars
// имплементира Iterator<Item=char>
fn main() { let string = String::from("abc"); let chars = string.chars(); // std::str::Chars // имплементира Iterator- }
Итерация
1
2
3
4
5
6
7
let string = String::from("abc");
let chars = string.chars();
println!("{:?}", chars.next());
println!("{:?}", chars.next());
println!("{:?}", chars.next());
println!("{:?}", chars.next());
error[E0596]: cannot borrow `chars` as mutable, as it is not declared as mutable --> src/bin/main_60db710cd3400136fe0738fe2a2b6f013018308d.rs:3:5 | 3 | let chars = string.chars(); | ^^^^^ not mutable 4 | 5 | println!("{:?}", chars.next()); | ----- cannot borrow as mutable 6 | println!("{:?}", chars.next()); | ----- cannot borrow as mutable 7 | println!("{:?}", chars.next()); | ----- cannot borrow as mutable 8 | println!("{:?}", chars.next()); | ----- cannot borrow as mutable | help: consider changing this to be mutable | 3 | let mut chars = string.chars(); | +++ For more information about this error, try `rustc --explain E0596`. error: could not compile `rust` (bin "main_60db710cd3400136fe0738fe2a2b6f013018308d") due to 1 previous error
fn main() { let string = String::from("abc"); let chars = string.chars(); println!("{:?}", chars.next()); println!("{:?}", chars.next()); println!("{:?}", chars.next()); println!("{:?}", chars.next()); }
Итерация
1
2
3
4
5
6
7
let string = String::from("abc");
let mut chars = string.chars(); // Mutable!
println!("{:?}", chars.next());
println!("{:?}", chars.next());
println!("{:?}", chars.next());
println!("{:?}", chars.next());
Some('a') Some('b') Some('c') None
fn main() { let string = String::from("abc"); let mut chars = string.chars(); // Mutable! println!("{:?}", chars.next()); println!("{:?}", chars.next()); println!("{:?}", chars.next()); println!("{:?}", chars.next()); }
Итерация
1
2
3
4
5
6
let string = String::from("abc");
let mut chars = string.chars();
while let Some(c) = chars.next() {
println!("{:?}", c);
}
'a' 'b' 'c'
fn main() { let string = String::from("abc"); let mut chars = string.chars(); while let Some(c) = chars.next() { println!("{:?}", c); } }
Итерация
1
2
3
4
5
6
let string = String::from("abc");
let mut chars = string.chars();
for c in chars {
println!("{:?}", c);
}
'a' 'b' 'c'
fn main() { let string = String::from("abc"); let mut chars = string.chars(); for c in chars { println!("{:?}", c); } }
Итерация
1
2
3
4
5
6
let string = String::from("abc");
let chars = string.chars(); // Not Mutable!
for c in chars {
println!("{:?}", c);
}
'a' 'b' 'c'
fn main() { let string = String::from("abc"); let chars = string.chars(); // Not Mutable! for c in chars { println!("{:?}", c); } }
Итерация
1
2
3
4
5
let string = String::from("abc");
for c in string.chars() {
println!("{:?}", c);
}
'a' 'b' 'c'
fn main() { let string = String::from("abc"); for c in string.chars() { println!("{:?}", c); } }
Итерация
1
2
3
4
5
6
7
8
9
10
for loop_variable in iterator {
code()
}
{
let mut iter = iterator;
while let Some(loop_variable) = iter.next() {
code();
}
}
Итерация
Полезни методи - collect
Събира всички елементи от итератор в колекция
1
2
3
4
let iter = "Здравей! 😊".chars(); // std::str::Chars
let chars: Vec<char> = iter.collect();
println!("{:?}", chars);
['З', 'д', 'р', 'а', 'в', 'е', 'й', '!', ' ', '😊']
fn main() { let iter = "Здравей! 😊".chars(); // std::str::Chars let chars: Vec= iter.collect(); println!("{:?}", chars); }
Итерация
Полезни методи - collect
Трябва да се окаже типа на резултата
1
2
3
4
let iter = "Здравей! 😊".chars(); // std::str::Chars
let chars = iter.collect();
println!("{:?}", chars);
error[E0283]: type annotations needed --> src/bin/main_0d01af2b125ad1b3196100c75030d8c48051f4d1.rs:3:5 | 3 | let chars = iter.collect(); | ^^^^^ ------- type must be known at this point | = note: multiple `impl`s satisfying `_: FromIterator<char>` found in the `alloc` crate: - impl FromIterator<char> for Box<str>; - impl FromIterator<char> for String; note: required by a bound in `collect` --> /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/iter/traits/iterator.rs:1996:5 help: consider giving `chars` an explicit type | 3 | let chars: Vec<_> = iter.collect(); | ++++++++ For more information about this error, try `rustc --explain E0283`. error: could not compile `rust` (bin "main_0d01af2b125ad1b3196100c75030d8c48051f4d1") due to 1 previous error
fn main() { let iter = "Здравей! 😊".chars(); // std::str::Chars let chars = iter.collect(); println!("{:?}", chars); }
Итерация
Полезни методи - collect
Обикновенно е нужен само типа на колекцията. Типа на аргументите може да се отгатне
1
2
3
4
let iter = "Здравей! 😊".chars(); // std::str::Chars
let chars: Vec<_> = iter.collect();
println!("{:?}", chars);
['З', 'д', 'р', 'а', 'в', 'е', 'й', '!', ' ', '😊']
fn main() { let iter = "Здравей! 😊".chars(); // std::str::Chars let chars: Vec<_> = iter.collect(); println!("{:?}", chars); }
Заключение
Заключение
- Внимавайте с UTF-8! Обработката на низове изисква итерация през всички символи
Заключение
- Внимавайте с UTF-8! Обработката на низове изисква итерация през всички символи
- Тествайте си домашните с кирилица
Заключение
- Внимавайте с UTF-8! Обработката на низове изисква итерация през всички символи
- Тествайте си домашните с кирилица
- Вижте документацията на: