Chars and Substrings
Буквы (char)
Перевод букв в числа методом to_digit(RADIX) (RADIX=10 в десятичной системе) и их сумма:
fn main() {
const RADIX: u32 = 10;
let x = "134";
println!("{}", x.chars().map(|c| c.to_digit(RADIX).unwrap()).sum::<u32>()); }Перевод букв в коды ASCII и обратно:
println!("{}", 'a' as u8); // перевод символа в код ASCII
println!("{}", 97 as char); // число как символ
// перевод кода UTF-8 в символ (не все символы можно перевести):
println!("{:?}", std::char::from_u32(98).unwrap());
Первая и последняя буква в строке
Чтобы проверить или изменить 1-ую букву в строке (в том числе иероглиф или иной вариант алфавита), нужно строку переделать в вектор из букв:
let char_vec: Vec<char> = text.chars().collect();
if char_vec[0].is_lowercase() { .. }Для последней буквы есть метод last(), вешается на итератор chars(), возвращает Option<char>, так как последней буквы может и не быть:
println!("{}", "foobar".chars().last().unwrap()); // 'r'
Гласные / согласные буквы
Проверку нужно написать в виде функции:
fn is_vowel(c: char) -> bool {
c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' ||
c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U' }
let text = String::from("Aria");Сортировка букв в словах
Есть функции sort() и sort_unstable() (работает быстрее, но равные элементы может перемешивать) для вектора символов Vec<char>. Обе функции делают сортировку на месте, возвращают ().
let input = "zxyabc"; // сортировка Unicode тоже работает
let mut char2vec_iter = input.chars()
.collect::<Vec<char>>();
char2vec_iter.sort_unstable(); // сортировка на месте
// char2vec_iter.sort_by(|a,b| b.cmp(a)); // реверс-сортировка
// собираем назад String из Vec<char>
let sorted_string: String = char2vec_iter.into_iter().collect();
println!("{}", sorted_string); // "abcxyz"
chunks() и chunks_exact() разбиение строк на части
Аналогично массивам, строки можно разбить на части:
let text = "ПриветМир";
let chars = text.chars().collect::<Vec<char>>();
println!("Разбиваем строку на части по 3 символа:");
for chunk in chars.chunks(3) {
let s: String = chunk.iter().collect();
println!("{}", s);
// При
// вет
// Мир
Строковые срезы
Срезы позволяют взять часть строки, указав диапазон байтовых индексов.
- Синтаксис:
&string[start..end](гдеstart— начало,end— конец, не включительно). - Особенность: нужно вручную следить за границами байтов, иначе будет паника при попытке разрезать строку посреди многобайтового символа.
let text = "Hello, world!"; // тип &str
let text = String::from("Hello, world!"); // String
// Если у вас String, а не &str, нужно взять срез с помощью &:
let first_three = &text[0..3]; // первые 3 символа
let last_five = &text[text.len()-5..]; // последние 5 символов
println!("{}", first_three); // "Hel"
println!("{}", last_five); // "orld!"
Отрицательные индексы в Rust не поддерживаются, поэтому нужно вычислять вручную. Если указать только начало ([start..]), берётся всё до конца:
let world_and_more = &text[7..];
println!("{}", world_and_more); // "world!"
Если строка содержит многобайтовые символы (например, кириллицу или эмодзи), простые байтовые срезы могут вызвать панику. Для работы с символами (Unicode scalar values) используйте метод .chars():
let text = "Привет, мир!";
let chars: Vec = text.chars().collect(); // преобразуем в вектор символов
let privet: String = chars[0..6].iter().collect(); // собираем первые 6 символов
println!("{}", privet); // "Привет"
Метод .chars() возвращает итератор по символам, а .collect() собирает их в нужный тип (например, String).
.get(start..end) для безопасного извлечения
Если нет уверенности в границах, и надо избежать паники, подойдёт метод .get() вместо прямого среза. Он возвращает Option<&str>:
let text = "Hello, world!";
if let Some(substr) = text.get(0..5) {
println!("{}", substr); // "Hello"
} else {
println!("Ошибка: неверные границы"); }Библиотека substring
Для более прямого аналога substr можно использовать стороннюю библиотеку substring из crates.io. Добавьте в Cargo.toml:
[dependencies]
substring = "1.4.5"Пример использования:
use substring::Substring;
let text = "Hello, world!";
let hello = text.substring(0, 5);
println!("{}", hello); // "Hello"
let world = text.substring(7, 12);
println!("{}", world); // "world"
- Преимущество: проще для новичков, не нужно беспокоиться о байтовых границах.
- Недостаток: добавляет внешнюю зависимость.
Примеры
Разворот букв в словах
Дана строка с пробелами между словами. Необходимо развернуть слова в строке наоборот, при этом сохранить пробелы.
fn reverse_words_split(str: &str) -> String {
str.to_string()
.split(" ") // при разделении split() множественные пробелы сохраняются
.map(|x| x.chars().rev().collect::<String>()) // разворот слов+сбор в строку
.collect::<Vec<String>>(). // сбор всего в вектор
.join(" ") // превращение вектора в строку
}
fn main() {
let word: &str = "The quick brown fox jumps over the lazy dog.";
println!("{}",reverse_words_split(&word));
}
// ehT kciuq nworb xof spmuj revo eht yzal .god