String Iterators

Отображение части строки

Передавать владельца не нужно, передаём в &str:

let s = String::from("Hello World!");
let word = first_word(&s);
println!("The first word is: {}", word);
}

fn first_word(s: &String) -> &str { // передача строки по ссылке
let word_count = s.as_bytes();

for (i, &item) in word_count.iter().enumerate() {
    if item == b' ' {
    return &s[..i]; // возврат части строки как &str
    }
}
&s[..]  // обязательно указать возвращаемое значение, если условие в цикле выше ничего не вернёт (например, строка не содержит пробелов = вернуть всю строку)

‘Проход’ по строке итератором

Можно пройти по строке итератором chars() и его методами взятия N-го символа nth() спереди или nth_back() сзади:

let person_name = String::from("Alice");  
println!("The last character of string is: {}", match person_name.chars().nth_back(0) {  // ищем 1-ый символ с конца строки
        Some(i) => i.to_string(),  // если находим - превращаем в строку
        None => "Nothing found!".to_string(),  // не находим = сообщаем
    });  

matches() и rmatches(),

Возвращают итератор с теми частями строки, которые совпадают с заданным шаблоном:

let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect();  
assert_eq!(v, ["abc", "abc", "abc"]); // вывод слева-направо
  
let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect();  
assert_eq!(v, ["3", "2", "1"]); // вывод справа-налево

find() и rfind()

Возвращает Option<байт индекс 1го символа в строке слева-направо>, совпадающий с шаблоном. Либо возвращает None, если символ отсутствует в строке. rfind

fn duplicate_encode2(word: &str) -> String {
    let s = String::from(word).to_lowercase();
    s.chars()
        .map(|c| if s.find(c) == s.rfind(c) { '(' } else { ')' })
        .collect() } // если у символа есть дубли => замена на '(', 
                     // иначе на ')'

fn main() {
    println!("{}", duplicate_encode("rEcede"));
}

Примеры

Повтор части строки n раз

Новый подход использует std::repeat

fn main() {
    let repeated = "Repeat".repeat(4);
    println!("{}", repeated); // RepeatRepeatRepeatRepeat
} 

Старый вариант через итератор - позволяет бесконечно отдавать любое значение (как generic):

use std::iter;

fn main() {
    let repeated: String = iter::repeat("Repeat").take(4).collect();
    println!("{}", repeated);
}

Удаление пробелов в строке String

Use split(' '), filter out empty entries then re-join by space:

s.trim()
    .split(' ')
    .filter(|s| !s.is_empty())
    .collect::<Vec<_>>()
    .join(" ")

// Using itertools:
use itertools::Itertools;
s.trim().split(' ').filter(|s| !s.is_empty()).join(" ")

// Using split_whitespace, allocating a vector & string
pub fn trim_whitespace_v1(s: &str) -> String {
    let words: Vec<_> = s.split_whitespace().collect();
    words.join(" ")
}

Озаглавить каждое слово в предложении

В заданной фразе озаглавить каждое слово. Если результат больше 140 символов или пустой, вернуть None:

fn capitalize_first_letter(s: &str) -> Option<String> {
    let res = s
        .split_whitespace()
        .map(capital) // каждое слово передать в функцию capital()
        .collect::<Vec<String>>() // собрать в вектор
        .join(" "); // потому что вектор можно собрать в string с join()
    if res.len() < 141 || !res.is_empty() { // проверка длины
        Some(res)
    } else { None } }

fn capital(word: &str) -> String {
    let mut lword = word.to_ascii_lowercase();
    // изменить НА МЕСТЕ - прямо в этой строке (быстрее всего):
    lword[0..1].make_ascii_uppercase(); 
    lword // вернуть итоговую строку
}