Как извлечь первый/последний буквенно-цифровой символ из строки

У меня есть, казалось бы, простая проблема извлечения первого и последнего буквенно-цифрового символа из строки в Rust. Пожалуйста, рассмотрите мой минималистичный пример ниже:

fn main() {
    let s: String = "Peace to the world!".to_string();

    // check: string is not empty
    if !s.is_empty() {

        let s    = s.to_uppercase();

        let fidx = s.find(char::is_alphanumeric).unwrap();
        println!("fidx: {fidx}");

        let fchar = s.get(fidx..fidx).unwrap();
        println!("fchar: {fchar}");

        let lidx = s.rfind(char::is_alphanumeric).unwrap();
        println!("lidx: {lidx}");

        let lchar = s.get(lidx..lidx).unwrap();
        println!("lchar: {lchar}");
    }
}

Мой код возвращает пустые символы как для fchar, так и для lchar. Как мне получить эти символы из моей строки? Не могли бы вы также проверить мой код? Я не уверен, что это самое короткое и элегантное решение.

Для &str и других фрагментов .get(x).unwrap() можно записать как [x]

cafce25 04.04.2024 13:25

Обратите внимание, что fidx..fidx — это эксклюзивный диапазон, поэтому в настоящее время вы пытаетесь извлечь диапазоны, где c в fidx <= c < fidx, который всегда пуст. Пожалуйста, попробуйте с fidx..=fidx.

SirDarius 04.04.2024 13:29

Все в порядке! С этой записью &s[fidx..=fidx] всё работает, но это очень громоздко. Есть ли лучшее, более элегантное решение?

mabalenk 04.04.2024 13:30
В чем разница между методом "==" и equals()
В чем разница между методом "==" и equals()
Это один из наиболее часто задаваемых вопросов новичкам на собеседовании. Давайте обсудим его на примере.
Замена символа по определенному индексу в JavaScript
Замена символа по определенному индексу в JavaScript
В JavaScript существует несколько способов заменить символ в строке по определенному индексу.
0
3
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

fidx..fidx всегда пусто, поскольку второе значение является исключительным.

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

let fchar = &s[fidx..=fidx];

Но технически это не дает вам первый символ, это дает вам &str первого символа и работает только в том случае, если его ширина в представлении UTF-8 составляет ровно 1 байт.

Поэтому вместо этого, если вам не нужен индекс, вы можете получить первый char, который соответствует критерию, с помощью этого:

let fchar = s.chars().find(|c| c.is_alphanumeric()).unwrap();

Или оба сразу с этим:

let (fidx, fchar) = s.char_indices().find(|(_, c)| c.is_alphanumeric()).unwrap();

Примечание. .char_indices() дает вам итератор по индексу байта и соответствующему символу, который вычисляет ваш код. Если вам нужен индекс символа, вы можете заменить его на .chars().enumerate()

В последнем случае просто замените find на rfind:

let lchar = s.chars().rfind(|c| c.is_alphanumeric()).unwrap();
let (lidx, lchar) = s.char_indices().rfind(|(_, c)| c.is_alphanumeric()).unwrap();

Можете ли вы объяснить детали закрытия? Что происходит в замыкающих телах?

mabalenk 04.04.2024 13:38

Он вызывает char::is_alphanumeric(c)⁉ Не знаю, что тут объяснять, поскольку это простой вызов функции.

cafce25 04.04.2024 13:39

Зачем нам нужна ссылка |&c| в аргументах закрытия? Что означает это обозначение |&(_, c)|? Что мы отбрасываем индекс?

mabalenk 04.04.2024 13:43

А, вы имеете в виду аргументы, &c — это шаблон ссылки, он разыменовывает переданный аргумент, что необходимо, потому что Iterator::find дает нам только ссылки на элементы. str::find может давать нам значения только потому, что знает тип и что char это Copy, поэтому он просто дает вам копию. Аналогично, &(_, c) — это шаблон, и да, для этого шаблона мы отбрасываем индекс, который является первым элементом кортежа (он нам все равно не нужен для проверки).

cafce25 04.04.2024 13:51

Другие вопросы по теме