• rust字符串


    标准库提供了String结构体表示字符串。
    String实际上就是Vec的封装。唯一的不同是String的方法假定Vec中的二进制都是utf8编码的

    pub struct String {
         vec: Vec,
    }
    
    • 1
    • 2
    • 3

    一、定义String

    1.使用new方法创建空字符串

    let string = String::new();
    
    • 1

    2.使用from方法创建

    let hello = String::from("Hello");
    let hello = String::from("你好");
    
    • 1
    • 2

    3.使用to_string方法创建

    let one = 1.to_string(); // 整数到字符串
    let float = 1.3.to_string(); // 浮点数到字符串
    let slice = "hello".to_string(); // 字符串切片到字符串
    
    • 1
    • 2
    • 3

    4.使用format!宏

    let s = format!("{}{}{}", 1, 'a', "bc");
    
    • 1

    二、使用String

    因为String实现了Deref Target=str,所以String自动实现了str的所有方法。
    (一)长度
    有两个长度,字节数和字符数。
    因为使用的utf8编码,所以一个字符可能有多个字节,所以字节数和字符数可能不相等。
    1.字节数
    len函数返回的是字节数

    let s = "hello";
    let len = s.len();
    这里len的值是5。
    
    let s = "你好";
    let len = s.len();
    这里len的值是6。因为中文是UTF-8编码的,每个字符3个字节,所以长度为6。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.字符数
    想要获取字符数比较麻烦。先用chars()返回一个迭代器,然后再返回这个迭代器的长度。

    chars
    chars返回一个迭代器,元素类型是char。
    例子

    let s = "hello你好";
    let len = s.chars().count();
    这里len的值是7,因为一共有7个字符。
    
    • 1
    • 2
    • 3

    (二)获取字符
    String不支持[]下标访问
    为什么不支持呢?因为字符编码用的是utf8,一个字符占多个字节。而使用下标只能获得一个字节,显然这一个字节是不能代表字符的。
    无效的Rust代码:

    let hello = "你好";
    let answer = &hello[0];
    “你”是三个字节,而hello[0]只是一个字节,所以这是错误的。
    
    • 1
    • 2
    • 3

    那么该如何获取字符?
    首先要明确获取字符还是字节。
    1.获取字符,也就是char
    (1)使用 chars 方法
    获取单字符
    先使用chars返回一个迭代器,然后使用迭代器的nth方法获取第n个字符,索引从0开始。

    实例

    fn main() {
        let s = String::from("EN中文");
        let a = s.chars().nth(2);
        println!("{:?}", a);
    }
    运行结果:
    Some('中')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    遍历所有字符
    实例

    fn main() {
        let s = String::from("hello中文");
        for c in s.chars() {
            println!("{}", c);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (2)使用char_indices
    返回一个迭代器,元素是(i, c),i是索引,c是字符。
    例子

    let word = "goodbye";
    let count = word.char_indices().count();
    assert_eq!(7, count);
    let mut char_indices = word.char_indices();
    assert_eq!(Some((0, 'g')), char_indices.next());
    assert_eq!(Some((1, 'o')), char_indices.next());
    assert_eq!(Some((2, 'o')), char_indices.next());
    assert_eq!(Some((3, 'd')), char_indices.next());
    assert_eq!(Some((4, 'b')), char_indices.next());
    assert_eq!(Some((5, 'y')), char_indices.next());
    assert_eq!(Some((6, 'e')), char_indices.next());
    assert_eq!(None, char_indices.next());
    for (i, c) in word.char_indices(){
        println!("{}", c);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.获取字节,也就是u8
    (1)使用 bytes 方法。
    bytes
    返回迭代器,元素是u8
    例子

    let s = String::from("你好");
    let mut bytes = s.bytes();
    for b in bytes {
         println!("{b}");
    }
    打印
    228
    189
    160
    229
    165
    189
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (2)使用as_bytes
    as_bytes
    将String转换成&[u8]。
    与此方法的相反的是from_utf8。
    例子

    let s = String::from("你好");
    for i in s.as_bytes() {
         println!("{}", i);
    }
    
    • 1
    • 2
    • 3
    • 4

    (三)截取子串
    1.通过字节位置截取
    可以使用 [] 和一个range来创建含特定字节的字符串切片
    实例

    fn main() {
         let s = String::from("EN中文");
         let sub = &s[0..2];
         println!("{}", sub);
    }
    运行结果:
    EN
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    使用这种方法截取时,必须保证字节位置是char的边界,否则会崩溃
    实例

    fn main() {
         let s = String::from("EN中文");
         let sub = &s[0..3];     //会崩溃
         println!("{}", sub);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.通过字符位置截取

    fn substr(s: &str, start: usize, length: usize) -> String {
         s.chars().skip(start).take(length).collect()
    }
    fn main() {
         let s1 = "中国-China";
         println!("{:?}", substr(s1, 1, 100));
         println!("{:?}", substr(s1, 0, 2));
         let s2 = String::from("中国-China");
         println!("{:?}", substr(&s2, 1, 100));
         println!("{:?}", substr(&s2, 0, 2));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    (四)拼接
    1.使用push追加char

    let mut s = String::from("run");
    s.push('!'); // 追加字符
    
    • 1
    • 2

    2.使用push_str追加&str

    let mut s = String::from("run");
    s.push_str("oob"); // 追加字符串切片
    
    • 1
    • 2

    3.用 + 号拼接String

    let s1 = String::from("Hello, ");
    let s2 = String::from("world!");
    let s3 = s1 + &s2; // 注意s1被移动了,不能继续使用
    
    • 1
    • 2
    • 3

    这个语法也可以拼接&str:

    let s1 = String::from("tic");
    let s2 = String::from("tac");
    let s3 = String::from("toe");
    let s = s1 + "-" + &s2 + "-" + &s3;
    
    • 1
    • 2
    • 3
    • 4

    4.使用format!宏

    let s1 = String::from("tic");
    let s2 = String::from("tac");
    let s3 = String::from("toe");
    let s = format!("{}-{}-{}", s1, s2, s3);
    
    • 1
    • 2
    • 3
    • 4

    (五)插入
    insert
    在指定字节位置插入一个字符。
    Panics
    如果idx大于String的长度,或者它不在char边界上,就会出现panics。
    例子

    let mut s = String::with_capacity(3);
    s.insert(0, 'f');
    s.insert(1, 'o');
    s.insert(2, 'o');
    assert_eq!("foo", s);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    insert_str
    在指定字节位置处插入&str。
    Panics
    如果idx大于String的长度,或者它不在char边界上,就会出现panics。
    例子

    let mut s = String::from("bar");
    s.insert_str(0, "foo");
    assert_eq!("foobar", s);
    
    • 1
    • 2
    • 3

    (六)删除
    truncate
    将此String缩短为指定的字节长度。
    如果new_len大于字符串的当前长度,则无效。
    Panics
    如果new_len不位于char边界上,就会出现panics。
    例子

    let mut s = String::from("hello");
    s.truncate(2);
    assert_eq!("he", s);
    
    • 1
    • 2
    • 3

    pop
    删除最后一个字符并返回它。
    如果String为空,则返回None。
    例子

    let mut s = String::from("foo");
    assert_eq!(s.pop(), Some('o'));
    assert_eq!(s.pop(), Some('o'));
    assert_eq!(s.pop(), Some('f'));
    assert_eq!(s.pop(), None);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    remove
    从指定字节位置删除char并将其返回。
    Panics
    如果idx大于或等于String的长度,或者它不位于char边界上,就会出现panics。
    例子

    let mut s = String::from("foo");
    assert_eq!(s.remove(0), 'f');
    assert_eq!(s.remove(1), 'o');
    assert_eq!(s.remove(0), 'o');
    
    • 1
    • 2
    • 3
    • 4

    retain
    仅保留特定的字符。
    换句话说,使f© 返回false,来删除所有字符c。
    例子

    let mut s = String::from("f_o_ob_ar");
    s.retain(|c| c != '_');
    assert_eq!(s, "foobar");
    使用外部状态来确定要保留哪些元素。
    let mut s = String::from("abcde");
    let keep = [false, true, true, false, true];
    let mut iter = keep.iter();
    s.retain(|_| *iter.next().unwrap());
    assert_eq!(s, "bce");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    clear
    删除所有内容。
    虽然这意味着String的长度为零,但它并未触及其容量。
    例子

    let mut s = String::from("foo");
    s.clear();
    assert!(s.is_empty());
    assert_eq!(0, s.len());
    assert_eq!(3, s.capacity());
    
    • 1
    • 2
    • 3
    • 4
    • 5

    drain
    批量删除指定范围,并以迭代器的形式返回所有删除的字符。
    返回的迭代器在字符串上保留一个可变借用以优化其实现。
    Panics
    如果起始点或结束点不在char边界上,或超出边界,就会出现panic。
    Leaking
    如果返回的迭代器离开作用域而没有被丢弃 (例如,由于core::mem::forget),则字符串可能仍包含任何耗尽字符的副本,或者可能任意丢失字符,包括范围外的字符。
    例子

    let mut s = String::from("αis alpha, βis beta");
    let beta_offset = s.find('β').unwrap_or(s.len());
    // 删除范围直到字符串中的 β
    let t: String = s.drain(..beta_offset).collect();
    assert_eq!(t, "αis alpha, ");
    assert_eq!(s, "βis beta");
    // 全范围清除字符串,就像 `clear()` 一样
    s.drain(..);
    assert_eq!(s, "");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    trim
    返回除去前导和尾随空格的字符串切片。
    ‘Whitespace’ 是根据Unicode派生的核心属性White_Space的术语定义的,该属性包括换行符。
    例子

    let s = "\n Hello\tworld\t\n";
    assert_eq!("Hello\tworld", s.trim());
    
    • 1
    • 2

    trim_start
    返回除去前导空格的字符串切片。
    ‘Whitespace’ 是根据Unicode派生的核心属性White_Space的术语定义的,该属性包括换行符。
    文字方向性
    字符串是字节序列。start在此上下文中表示该字节字符串的第一个位置; 对于从左到右的语言 (例如英语或俄语),这将是左侧; 对于从右到左的语言 (例如阿拉伯语或希伯来语),这将是右侧。
    例子

    let s = "\n Hello\tworld\t\n";
    assert_eq!("Hello\tworld\t\n", s.trim_start());
    Directionality:
    let s = " English ";
    assert!(Some('E') == s.trim_start().chars().next());
    let s = " עברית ";
    assert!(Some('ע') == s.trim_start().chars().next());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    trim_end
    返回除去尾随空格的字符串切片。
    ‘Whitespace’ 是根据Unicode派生的核心属性White_Space的术语定义的,该属性包括换行符。
    文字方向性
    字符串是字节序列。end在此上下文中表示该字节字符串的最后位置; 对于从左到右的语言 (例如英语或俄语),这将在右侧; 对于从右到左的语言 (例如阿拉伯语或希伯来语),将在左侧。
    例子

    let s = "\n Hello\tworld\t\n";
    assert_eq!("\n Hello\tworld", s.trim_end());
    Directionality:
    let s = " English ";
    assert!(Some('h') == s.trim_end().chars().rev().next());
    let s = " עברית ";
    assert!(Some('ת') == s.trim_end().chars().rev().next());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (七)转换
    as_str
    将String转换为&str。
    例子

    let s = String::from("foo");
    assert_eq!("foo", s.as_str());
    
    • 1
    • 2

    as_mut_str
    将String转换为&mut str。
    例子

    let mut s = String::from("foobar");
    let s_mut_str = s.as_mut_str();
    s_mut_str.make_ascii_uppercase();
    assert_eq!("FOOBAR", s_mut_str);
    
    • 1
    • 2
    • 3
    • 4

    parse
    将此字符串切片解析为另一种类型。
    由于parse非常通用,因此可能导致类型推断问题。需要指定类型或使用turbofish语法
    parse可以解析为任何实现FromStr trait的类型。
    Errors
    如果无法将此字符串切片解析为所需的类型,则将返回Err。
    例子

    let four: u32 = "4".parse().unwrap();
    assert_eq!(4, four);
    使用turbofish
    let four = "4".parse::();
    assert_eq!(Ok(4), four);
    无法解析:
    let nope = "j".parse::();
    assert!(nope.is_err());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    (八)替换
    replace_range
    删除字符串中的指定字节范围,并将其替换为给定的字符串。
    Panics
    如果起始点或结束点不在char边界上,或超出边界,就会出现panic。
    例子

    let mut s = String::from("αis alpha, βis beta");
    let beta_offset = s.find('β').unwrap_or(s.len());
    // 替换范围直到字符串中的 β
    s.replace_range(..beta_offset, "Αis capital alpha; ");
    assert_eq!(s, "Αis capital alpha; βis beta");
    
    • 1
    • 2
    • 3
    • 4
    • 5

    replace
    用另一个字符串替换模式的所有匹配项。
    例子

    let s = "this is old";
    assert_eq!("this is new", s.replace("old", "new"));
    assert_eq!("than an old", s.replace("is", "an"));
    当模式不匹配时,它将此字符串切片作为String返回:
    let s = "this is old";
    assert_eq!(s, s.replace("cookie monster", "little lamb"));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    replacen
    用另一个字符串替换模式的前N个匹配项
    例子

    let s = "foo foo 123 foo";
    assert_eq!("new new 123 foo", s.replacen("foo", "new", 2));
    assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3));
    assert_eq!("foo foo new23 foo", s.replacen(char::is_numeric, "new", 1));
    当模式不匹配时,它将此字符串切片作为String返回:
    let s = "this is old";
    assert_eq!(s, s.replacen("cookie monster", "little lamb", 10));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (九)分割
    split_off
    在给定的字节索引处将字符串拆分为两个。
    返回新分配的String。self包含字节 [0, at),返回的String包含字节 [at, len)。at必须位于UTF-8代码点的边界上。
    请注意,self的容量不会改变。
    Panics
    如果at不在UTF-8代码点边界上,或者它超出字符串的最后一个代码点,就会出现panics。
    例子

    let mut hello = String::from("Hello, World!");
    let world = hello.split_off(7);
    assert_eq!(hello, "Hello, ");
    assert_eq!(world, "World!");
    
    • 1
    • 2
    • 3
    • 4

    split_whitespace
    用空格分割字符串切片。
    返回的迭代器将返回作为原始字符串切片的子切片的字符串切片,并以任意数量的空格分隔。
    ‘Whitespace’ 是根据Unicode派生核心属性White_Space的条款定义的。 如果只想在ASCII空格上分割,请使用split_ascii_whitespace。
    例子

    let mut iter = "A few words".split_whitespace();
    assert_eq!(Some("A"), iter.next());
    assert_eq!(Some("few"), iter.next());
    assert_eq!(Some("words"), iter.next());
    assert_eq!(None, iter.next());
    考虑所有类型的空白:
    let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace();
    assert_eq!(Some("Mary"), iter.next());
    assert_eq!(Some("had"), iter.next());
    assert_eq!(Some("a"), iter.next());
    assert_eq!(Some("little"), iter.next());
    assert_eq!(Some("lamb"), iter.next());
    assert_eq!(None, iter.next());
    如果字符串为空或全为空白,则迭代器不产生字符串切片:
    assert_eq!("".split_whitespace().next(), None);
    assert_eq!(" ".split_whitespace().next(), None);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    split_ascii_whitespace
    用ASCII空格分割字符串切片。
    返回的迭代器将返回作为原始字符串切片的子切片的字符串切片,并以任意数量的ASCII空格分隔。
    要改为按Unicode Whitespace进行拆分,请使用split_whitespace。
    例子

    let mut iter = "A few words".split_ascii_whitespace();
    assert_eq!(Some("A"), iter.next());
    assert_eq!(Some("few"), iter.next());
    assert_eq!(Some("words"), iter.next());
    assert_eq!(None, iter.next());
    考虑所有类型的ASCII空白:
    let mut iter = " Mary had\ta little \n\t lamb".split_ascii_whitespace();
    assert_eq!(Some("Mary"), iter.next());
    assert_eq!(Some("had"), iter.next());
    assert_eq!(Some("a"), iter.next());
    assert_eq!(Some("little"), iter.next());
    assert_eq!(Some("lamb"), iter.next());
    assert_eq!(None, iter.next());
    如果字符串为空或全部为ASCII空格,则迭代器不产生字符串切片:
    assert_eq!("".split_ascii_whitespace().next(), None);
    assert_eq!(" ".split_ascii_whitespace().next(), None);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    (十)contains
    如果包含模式,则返回true。否则返回false。
    模式 可以是 &str,char,&[char],也可以是确定字符是否匹配的函数或闭包。
    例子

    let bananas = "bananas";
    assert!(bananas.contains("nana"));
    assert!(!bananas.contains("apples"));
    
    • 1
    • 2
    • 3

    starts_with
    如果以模式开头,则返回true。否则返回false。
    模式 可以是 &str,char,&[char],也可以是确定字符是否匹配的函数或闭包。
    例子

    let bananas = "bananas";
    assert!(bananas.starts_with("bana"));
    assert!(!bananas.starts_with("nana"));
    
    • 1
    • 2
    • 3

    ends_with
    如果模式结尾,则返回true。否则返回false。
    模式 可以是 &str,char,&[char],也可以是确定字符是否匹配的函数或闭包。
    例子

    let bananas = "bananas";
    assert!(bananas.ends_with("anas"));
    assert!(!bananas.ends_with("nana"));
    
    • 1
    • 2
    • 3

    (十一)其他
    is_empty
    如果此String的长度为零,则返回true,否则返回false。

    let mut v = String::new();
    assert!(v.is_empty());
    v.push('a');
    assert!(!v.is_empty());
    
    • 1
    • 2
    • 3
    • 4

    lines
    返回一个迭代器,迭代器元素是&str。
    行以\n或\r\n结尾。最后一行的结尾是可选的。
    迭代器返回的行中会去掉\n或\r\n。
    例子

    let text = "foo\r\nbar\n\nbaz\n";
    let mut lines = text.lines();
    assert_eq!(Some("foo"), lines.next());
    assert_eq!(Some("bar"), lines.next());
    assert_eq!(Some(""), lines.next());
    assert_eq!(Some("baz"), lines.next());
    assert_eq!(None, lines.next());
    
    let text = "foo\nbar\n\r\nbaz";
    let mut lines = text.lines();
    assert_eq!(Some("foo"), lines.next());
    assert_eq!(Some("bar"), lines.next());
    assert_eq!(Some(""), lines.next());
    assert_eq!(Some("baz"), lines.next());
    assert_eq!(None, lines.next());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    Docker创建FTP服务器
    ADO.NET实体数据模型-DatabaseFirst
    简单聊聊ThreadLocal吧
    FreeRTOS-链表的源码解析
    EI论文程序:Adaboost-BP神经网络的回归预测算法,可作为深度学习对比预测模型,丰富实验内容,自带数据集,直接运行!
    大屏可视化!2022新趋势!
    WebRTC系列-SDP之setLocalDescription(2)
    【Java】@RestControllerAdvice 注解
    Vue路由&nodeJS环境搭建
    SpringBoot整合RabbitMQ实现消息延迟队列
  • 原文地址:https://blog.csdn.net/inxunxun/article/details/133111044