我想在Rust中创建一个子字符串。它以字符串的出现开始,以字符串末尾减去四个字符或某个字符结束。
我的第一个方法是
string[string.find("pattern").unwrap()..string.len()-5]
这是错误的,因为Rust的字符串是有效的UTF-8,因此是字节而不是基于字符的。
我的第二种方法是正确的但是过于冗长:
let start_bytes = string.find("pattern").unwrap();
let mut char_byte_counter = 0;
let result = line.chars()
.skip_while(|c| {
char_byte_counter += c.len_utf8();
return start_bytes > char_byte_counter;
})
.take_while(|c| *c != '<')
.collect::<String>();
是否有更简单的方法来创建子串?我找不到标准库的任何部分吗?
答案 0 :(得分:8)
我不记得其他语言中的内置库函数是否按照您想要的方式工作(给我两个模式之间的子串,如果第二个不存在,则在第一个和最后一个之间)。 我想你无论如何都要编写一些自定义逻辑。
相当于“substring”函数的关闭是切片。然而(正如你所发现的)它适用于字节,而不是unicode字符,所以你必须小心索引。在"Löwe"
中,'e'位于(字节)索引4处,而不是3(playground)。但你仍然可以在你的情况下使用它,因为你没有直接使用索引(使用find
代替...找到你需要的索引)
以下是切片的方法(红利,你不需要重新分配其他String
):
// adding some unicode to check that everything works
// also ouside of ASCII
let line = "asdfapatterndf1老虎23<12";
let start_bytes = line.find("pattern").unwrap();
let mut result = &line[start_bytes..]; // result is from "pattern" to
// the end, so "patterndf1老虎23<12"
// if there's a < let's check its byte index
if let Some(end) = result.find("<") {
// and re-slice line accordingly (now result = "patterndf1老虎23")
result = &line[start_bytes.. start_bytes+end];
}