String 如何交换字符串中的两个字符?
我想写一个函数,如下所示:String 如何交换字符串中的两个字符?,string,rust,String,Rust,我想写一个函数,如下所示: 输入:字符串A,整数i,0CharRange 给定字节位置和str,返回上一个字符及其位置 这两种方法结合在一起,让我们可以前后查看字符串,这正是我们想要的 但是等等,还有更多!DK指出了一个带有上述代码的角落案例。如果输入包含任何字符,它们可能会与它们组合的字符分离 现在,这个问题是关于生锈的,而不是Unicode,所以我不会详细讨论它。您现在需要知道的是,锈迹能够: fn图形索引(&self,扩展为:bool)->图形索引 返回对self及其字节偏移
- 输入:字符串A,整数i,0
- 输出:字符位于(i-1)的字符串A与字符位于i的字符串A交换
let mut swapped = input_str[0..i].to_string();
swapped.push(input_str.char_at(i));
swapped.push(input_str.char_at(i - 1));
swapped.push_str(&query[i..input_str.len()]);
但这只适用于ASCII字符串。我可以将其他解决方案想象为在UTF-32中转换为向量,在那里交换并转换回字符串,但这似乎需要很多额外的工作。这里有一个很好的解决方案:
use std::str::CharRange;
fn swap_chars_at(input_str: &str, i: usize) -> String {
// Pre-allocate a string of the correct size
let mut swapped = String::with_capacity(input_str.len());
// Pluck the previous character
let CharRange { ch: prev_ch, next: prev } = input_str.char_range_at_reverse(i);
// Pluck the current character
let CharRange { ch, next } = input_str.char_range_at(i);
// Put them back
swapped.push_str(&input_str[..prev]);
swapped.push(ch);
swapped.push(prev_ch);
swapped.push_str(&input_str[next..]);
// Done!
swapped
}
#[test]
fn smoke_test() {
let s = swap_chars_at("lyra", 2);
assert_eq!(s, "lrya");
}
#[test]
fn unicode() {
// 'ç' takes up 2 bytes in UTF-8
let s = swap_chars_at("ça va?", 2);
assert_eq!(s, "aç va?");
}
#![allow(unstable)] // `GraphemeIndices` is unstable
fn swap_graphemes_at(input_str: &str, i: usize) -> String {
// Pre-allocate a string of the correct size
let mut swapped = String::with_capacity(input_str.len());
// Find the grapheme at index i
let (_, gr) = input_str.grapheme_indices(true)
.find(|&(index, _)| index == i)
.expect("index does not point to a valid grapheme");
// Find the grapheme just before it
let (prev, prev_gr) = input_str.grapheme_indices(true).rev()
.find(|&(index, _)| index < i)
.expect("no graphemes to swap with");
// Put it all back together
swapped.push_str(&input_str[..prev]);
swapped.push_str(gr);
swapped.push_str(prev_gr);
swapped.push_str(&input_str[i+gr.len()..]);
// Done!
swapped
}
#[test]
fn combining() {
// Ensure that "c\u{327}" is treated as a single unit
let s = swap_graphemes_at("c\u{327}a va?", 3);
assert_eq!(s, "ac\u{327} va?");
}
从:
fn char\u range\u at(&self,start:usize)->CharRange
- 从字符串中提取一个字符并返回下一个字符的索引
fn char\u range\u反方向(&self,start:usize)->CharRange
- 给定字节位置和str,返回上一个字符及其位置
但是等等,还有更多!DK指出了一个带有上述代码的角落案例。如果输入包含任何字符,它们可能会与它们组合的字符分离 现在,这个问题是关于生锈的,而不是Unicode,所以我不会详细讨论它。您现在需要知道的是,锈迹能够:
fn图形索引(&self,扩展为:bool)->图形索引
- 返回对self及其字节偏移量的迭代
.find()
和.rev()
的健康应用,我们(希望)得出了这个正确的解决方案:
use std::str::CharRange;
fn swap_chars_at(input_str: &str, i: usize) -> String {
// Pre-allocate a string of the correct size
let mut swapped = String::with_capacity(input_str.len());
// Pluck the previous character
let CharRange { ch: prev_ch, next: prev } = input_str.char_range_at_reverse(i);
// Pluck the current character
let CharRange { ch, next } = input_str.char_range_at(i);
// Put them back
swapped.push_str(&input_str[..prev]);
swapped.push(ch);
swapped.push(prev_ch);
swapped.push_str(&input_str[next..]);
// Done!
swapped
}
#[test]
fn smoke_test() {
let s = swap_chars_at("lyra", 2);
assert_eq!(s, "lrya");
}
#[test]
fn unicode() {
// 'ç' takes up 2 bytes in UTF-8
let s = swap_chars_at("ça va?", 2);
assert_eq!(s, "aç va?");
}
#![allow(unstable)] // `GraphemeIndices` is unstable
fn swap_graphemes_at(input_str: &str, i: usize) -> String {
// Pre-allocate a string of the correct size
let mut swapped = String::with_capacity(input_str.len());
// Find the grapheme at index i
let (_, gr) = input_str.grapheme_indices(true)
.find(|&(index, _)| index == i)
.expect("index does not point to a valid grapheme");
// Find the grapheme just before it
let (prev, prev_gr) = input_str.grapheme_indices(true).rev()
.find(|&(index, _)| index < i)
.expect("no graphemes to swap with");
// Put it all back together
swapped.push_str(&input_str[..prev]);
swapped.push_str(gr);
swapped.push_str(prev_gr);
swapped.push_str(&input_str[i+gr.len()..]);
// Done!
swapped
}
#[test]
fn combining() {
// Ensure that "c\u{327}" is treated as a single unit
let s = swap_graphemes_at("c\u{327}a va?", 3);
assert_eq!(s, "ac\u{327} va?");
}
#![允许(不稳定)]/`GraphemeIndices`不稳定
fn swap_graphemes_at(input_str:&str,i:usize)->String{
//预先分配一个大小正确的字符串
让mut swapped=String::具有_容量(input_str.len());
//在索引i处查找grapheme
let(u,gr)=输入图素索引(真)
.find(|&(index,|)index==i)
.expect(“索引未指向有效的字符名”);
//在它之前找到我
let(prev,prev_gr)=输入图素索引(true).rev()
.find(|和(索引,|)索引
无可否认,这有点复杂。首先,它遍历输入,从i
中取出grapheme集群。然后它通过输入向后迭代(),选择索引为
的最右边的集群(即前一个集群)。最后,它把所有的东西重新组合起来
如果你真的很迂腐,还有更多的特殊情况需要处理。例如,如果字符串包含Windows换行符(“\r\n”
),那么我们可能不想交换它们。在希腊语中,当字母sigma(σ)位于单词(ς)的末尾时,它的书写方式不同,因此需要更好的算法在它们之间进行转换。别忘了那些
但是为了我们的理智起见,我们就到此为止。我认为你的代码中有一个错误——如果我读对了,它会将字符推到
I
和I-1
两次。我不相信这是正确的:你处理的是代码点,而不是图形,这是你应该做的。也就是说,如果您有组合代码点,它们将不会与您正在交换的代码点交换。@DK很好。我本来想说标准库没有grapheme拆分器,但事实证明它有。注释和编辑。令人印象深刻的编辑。这里真正的问题是,最初的问题是完全错误的:如果你做的任何事情都依赖于一个“角色”的具体概念,那么你可能只是在给自己制造麻烦。要做到正确是非常困难的。