rv.*_*tch 1 string whitespace replace rust
我正在处理需要 用单个空格替换多个空格的字符串 。看起来其中大多数只是人为错误,但我对处理此问题的理想方法感到好奇 - 最好是从&str到 的分配最少String。
到目前为止,这是我的方法如下:
const SPACE: &str = " ";
const TWO_SPACES: &str = " ";
/// Replace multiple spaces with a single space
pub fn trim_whitespace(s: &str) -> String {
let mut new_str: String = s.trim().to_owned();
while new_str.contains(TWO_SPACES) {
new_str = new_str.replace(TWO_SPACES, SPACE);
}
new_str
}
let result = trim_whitespace("Hello world! ");
assert_eq!(result, "Hello world!");
Run Code Online (Sandbox Code Playgroud)
编辑(10/2022):我有Python背景,做上面这样的事情是非常惯用的。例如, Python 中最快的版本(用单个空格替换多个空格)似乎是这样的:
const SPACE: &str = " ";
const TWO_SPACES: &str = " ";
/// Replace multiple spaces with a single space
pub fn trim_whitespace(s: &str) -> String {
let mut new_str: String = s.trim().to_owned();
while new_str.contains(TWO_SPACES) {
new_str = new_str.replace(TWO_SPACES, SPACE);
}
new_str
}
let result = trim_whitespace("Hello world! ");
assert_eq!(result, "Hello world!");
Run Code Online (Sandbox Code Playgroud)
您可以使用split(' '),过滤掉空条目,然后按空格重新加入:
s.trim()
.split(' ')
.filter(|s| !s.is_empty())
.collect::<Vec<_>>()
.join(" ")
// Or, using itertools:
use itertools::Itertools;
s.trim().split(' ').filter(|s| !s.is_empty()).join(" ")
Run Code Online (Sandbox Code Playgroud)
另一种可能性是使用String::retain()和删除连续的空格。它也应该更快,因为它只为修剪后的字符串分配一次:
pub fn trim_whitespace(s: &str) -> String {
let mut new_str = s.trim().to_owned();
let mut prev = ' '; // The initial value doesn't really matter
new_str.retain(|ch| {
let result = ch != ' ' || prev != ' ';
prev = ch;
result
});
new_str
}
Run Code Online (Sandbox Code Playgroud)
编辑:我很好奇,所以我用字符串对这里建议的所有版本进行了基准测试" a bb cc ddd "(当然,不同的字符串将具有不同的性能特征)。基准代码在这里(需要criterion和itertools)。
结果:
benches/trim_whitespace_replace
time: [846.02 ns 872.71 ns 901.90 ns]
benches/trim_whitespace_retain
time: [146.79 ns 153.07 ns 159.91 ns]
benches/trim_whitespace_split_space
time: [268.61 ns 277.44 ns 287.55 ns]
benches/trim_whitespace_split_space_itertools
time: [392.82 ns 406.92 ns 423.88 ns]
benches/trim_whitespace_split_whitespace
time: [236.38 ns 244.51 ns 254.00 ns]
benches/trim_whitespace_split_whitespace_itertools
time: [395.82 ns 413.59 ns 433.26 ns]
benches/trim_whitespace_split_whitespace_only_one_string
time: [146.25 ns 152.73 ns 159.94 ns]
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,您使用的版本replace()是最慢的。我使用的版本retain()和 @prog-fh 的更快版本是最快的(我预计他的版本会更快,因为它需要复制更少,但显然差异非常小,现代 CPU 复制小内存块的速度非常快。也许在较大的字符串中这将会出现)。有点令人惊讶的是,使用 itertools 的版本比仅使用标准库thenjoin()的版本慢,尽管不需要首先收集到向量中。我可以解释一下 - 这个版本在编译器上使用动态分派可能无法消除(但我不确定,需要检查程序集来验证),更糟糕的是,他们实际上可能需要分配更多,因为他们不提前不知道需要多少空间,他们还需要插入分隔符。collect()join()Display