Как найти в подстроке, начинающейся с определенного индекса в Rust?

Есть ли в стандартной библиотеке Rust функция find, которая ищет подстроку, начинающуюся с заданного индекса в строке? Так же, как indexOf в JavaScript.


person Community    schedule 19.02.2021    source источник
comment
Это похоже на Найти строку, начинающуюся с заданного индекса, но я найти ответы там неудовлетворительными, потому что они увязли в конкретном случае ОП.   -  person kmdreko    schedule 19.02.2021


Ответы (2)


Вы должны использовать str::find для подстроки и затем добавьте смещение обратно:

let s = "foobarfoo";
let index: Option<usize> = s[4..].find("foo").map(|i| i + 4);
println!("{:?}", index);
Some(6)
person kmdreko    schedule 19.02.2021
comment
Хотя это нормально для текста ascii, с этим возникает несколько проблем, если s содержит общий юникод, поскольку s[x..] - это фрагмент, начинающийся с байта x, а не с символа x^th. - person Michael Anderson; 19.02.2021
comment
@MichaelAnderson Верно, но чтобы избежать этого, это зависит от того, что 4 означает: первые четыре байта? первые четыре скалярных значения Юникода? первые четыре графемы? У всех разные ответы. Если мы нашли 4, сначала найдя первый b, то мы уже знаем его юникод-байтовое выравнивание. Также стоит отметить, что String.prototype.indexOf и std::string::find дают разные результаты при использовании unicode. - person kmdreko; 19.02.2021
comment
Все эти вещи могут давать разные ответы, и это нормально. Однако s[4..] может запаниковать - обычно это не тот ответ, который вам нужен. Я думаю, что если вы просто относитесь к обоим как к байтам, вы, по крайней мере, избегаете паники. - person Michael Anderson; 19.02.2021
comment
@MichaelAnderson, я думаю, 4 - это сумма позиции первого появления и длины искомой строки, поэтому она всегда должна быть правильной позицией unicode char. kmdreko, было бы хорошо, если бы вы заменили magic 4 вот такими вычислениями, чтобы было понятно новым пользователям ржавчины. - person Angelicos Phosphoros; 20.02.2021

Я могу думать о двух способах:

Используйте метод .get(), чтобы безопасно получить фрагмент строки ASCII, а затем примените к нему .find.

let s = "foobarfoo";
let res = s.get(4..).and_then(|s| s.find("foo").map(|i| i + 4));

Используйте match_indices для перебора совпадений и их индексов, а затем find_map тот, который соответствует первому условию.

let s = "foobarfoo";
let res = s.match_indices("foo").find_map(|(i, _)| (i >= 4).then(|| i));
  • Оба метода вернут Some(6).
  • Если индекс больше или равен длине строки, вы получите None.
person Jason    schedule 19.02.2021