代码之家  ›  专栏  ›  技术社区  ›  Asamartino

使用.as_bytes()反转字符串

  •  0
  • Asamartino  · 技术社区  · 3 年前

    我正试着把绳子倒过来。我使用的解决方案 this post 它起作用了。但我想尝试使用字节而不是如下所示的字形簇:

    fn reverse2(input: &str) -> String {
        input.as_bytes().iter().rev().collect()
    }
    

    很遗憾,我无法运行该函数 collect() 之后 rev() 。我不知道该用哪种方法。你会怎么做?

    2 回复  |  直到 3 年前
        1
  •  2
  •   Finomnis    3 年前

    正如你明确询问的 使用 chars() ,您必须将自己限制为ASCII字符串。

    pub fn reverse2(input: &str) -> String {
        // Reversing on byte-level only works with ASCII strings.
        assert!(input.is_ascii());
    
        let reversed_bytes: Vec<u8> = input.as_bytes().iter().copied().rev().collect();
        let reversed_string = unsafe {
            // SAFETY: This is guaranteed to be a valid UTF8 string, because:
            // - the input string is a valid ASCII string
            // - a reversed ASCII string is still a valid ASCII string
            // - an ASCII string is a valid UTF8 string
            String::from_utf8_unchecked(reversed_bytes)
        };
    
        return reversed_string;
    }
    

    如果您不喜欢 unsafe ,但它会带来一点开销:

    pub fn reverse2(input: &str) -> String {
        // Reversing on byte-level only works with ASCII strings.
        assert!(input.is_ascii());
    
        let reversed_bytes: Vec<u8> = input.as_bytes().iter().copied().rev().collect();
        let reversed_string = String::from_utf8(reversed_bytes).unwrap();
    
        return reversed_string;
    }
    

    优化:

    检查 is_ascii() 是一些开销。然而,这并不是严格要求的。

    UTF-8有一个特殊的属性:每个非ASCII字节都有值 128 及以上。因此,从技术上讲,只需简单地过滤掉所有等于或大于的值就足够了 128 :

    pub fn reverse2(input: &str) -> String {
        let reversed_bytes: Vec<u8> = input
            .as_bytes()
            .iter()
            .rev()
            .map(|&val| {
                if val < 128 {
                    val
                } else {
                    0x1a // replacement char
                }
            })
            .collect();
    
        let reversed_string = unsafe {
            // SAFETY: This is guaranteed to be a valid UTF8 string, because:
            // - `reversed_bytes` is guaranteed to be an ASCII string
            // - an ASCII string is a valid UTF8 string
            String::from_utf8_unchecked(reversed_bytes)
        };
    
        return reversed_string;
    }
    
    fn main() {
        let s = "abcde😃fghij";
        println!("{:?}", s.as_bytes());
    
        let reversed = reverse2(s);
        println!("{}", reversed);
        println!("{:?}", reversed.as_bytes());
    }
    
    [97, 98, 99, 100, 101, 240, 159, 152, 131, 102, 103, 104, 105, 106]
    jihgfedcba
    [106, 105, 104, 103, 102, 26, 26, 26, 26, 101, 100, 99, 98, 97]
    

    附加备注:

    考虑使用 .bytes() 而不是 .as_bytes().iter()

        2
  •  1
  •   Finomnis    3 年前

    首先你 应该 使用 .bytes() 而不是 .as_bytes().iter() 。其次,您需要反转字符,而不是字节,因为 &str 可能包含UTF-8,因此使用 .chars() 而不是 .bytes()(字节) 。第三,你不需要把它收集到一个变量中并返回一个变量,只需要返回收集的结果。第四,你不需要明确 return

    让我们总结一下我说的所有内容:

    pub fn reverse2(input: &str) -> String {
        input.chars()
             .rev()
             .collect()
    }
    
        3
  •  0
  •   Kaplan    3 年前

    以下是一个将 input 字符串转换为字节向量,因此 reverse 的函数 Vec 可以使用:

    pub fn reverse2(input: &str) -> String {
        let v = &mut input.to_string().into_bytes();
        v.reverse();
        std::str::from_utf8(v).unwrap().to_string()
    }
    

    这个 输入 字符串只能包含ASCII字符。

    Playground