rust字符串

本文详细介绍了Rust中的字符串类型,包括String和str的区别,字符串的构造方法,如from、new和to_string,以及遍历字符串的as_bytes和chars函数。此外,还探讨了字符串的容量操作、增删改查功能,字符串切片的使用,以及String和str之间的转换。最后,文章展示了字符串的实用方法,如转换为整数、字符串替换和切割等。
摘要由CSDN通过智能技术生成

0x001

字符串在rust中是一个对象特殊类型,可以理解为char的集合。

rust在核心语言中只有一种String类型,通过borrow的方式&str查看str。

string类型由rust的标准库提供,而不是编码为核心语言,是一种可增长、可变、拥有的、UTF-8编码的string类型。当rustaceans指的是rust中的“string”时,通常指的是string和string slice&str类型,而不仅仅是这些类型中的一种。尽管这一部分主要是关于string的,但这两种类型在rust的标准库中都被大量使用,并且string和string slice都是UTF-8编码的。

rust的标准库还包括许多其他string类型,例如osstring、osstr、cstring和cstr。可以为存储string提供更多的选项。这些类型指的是拥有和借用的变体,和string和str类型一样。例如,这些字符串可以以不同的编码存储文本,或者以不同的方式在内存中表示。

0x002 构造

字符串创建一般有三个方法

fn main(){
    let s = String::from("hello 世界”);

    let mut s1 = String::new();
    s1.push_str("hello 世界);
    //s1+="hello 世界"; //与上面的语句等价,即:追加字符串在后面

    let s2 = "hello 世界".to_string();

    
    println!("{}", s);
    println!("{}", s1);
    println!("{}", s2);
}

输出的结果都是一样的:

hello 世界
hello 世界
hello 世界

以上三种方法分别调用from函数,new函数以及to_string函数。

其中,from函数和to_string函数函数功能是等价的,只是调用的对象不同而已,作用都是从一个字符串字面量直接构造出一个String来。而new函数则是凭空生产一个String,而且是空的,如果想要让它存值,就得将它声明为可变的(mut),之后可以用push_str函数或者+=操作符来追加字符串。

除此之外还有一个函数with_capacity:

let s = String::with_capacity(100);

它的作用与new基本相同,唯一不同的是,这个函数需要一个参数来初始化其内部的内存大小,如果你事先知道自己需要多大的内存,那么建议你使用这个函数来构造一个String而不是new。

0x003 遍历

对字符串的遍历,用到两个函数:as_bytes与chars

1.遍历字符串的所有字节

fn main(){
    let s = String::from("hello 世界");
    for i in s.as_bytes(){
        println!("{}",i);
    }
}

输出结果:

104 101 108 108 111 32 228 184 150 231 149 140

hello分别对应前面的104 101 108 111 ,中间空格对应的是32,”世界“对应的是228 184 150 和231 149 140

2.使用chars函数遍历字符串

fn main(){
    let s =Strig::from("hello 世界");
    for i in s.chars(){
        println!("{}",i);
    }
}

输出结果

h e l l o  世 界

如果想要取出第几个字符,使用函数nth:

fn main(){
    let s = String::from("hello 世界");
    let mut m = s.chars();
    let c = m.nth(7);
    if let Some(t) = c { //取出返回值中携带的字符
        println!("{}",t);
    }
}

输出结果: 界

//更简洁的写法
fn main(){
    let s = String::from("hello 世界");
    let c = s.chars().nth(7);
    if let Some(t) = c {
        println!("{}", t);
    }
}

还能更简洁:

fn main(){
    let s = String::from("hello 世界");
    let c = s.chars().nth(7).unwrap();
    println!("{}", c);
}

unwrap函数是option这个trait的一个函数,等价于:

fn main(){
    let s = String::from("hello 世界");
    let c = s.chars().nth(7);
    let r = match c {
        Some(t) => t,
        None => panic!("")
    };
    println!("{}", r);
}
    

0x004 容量操作

字符串为实现内容可变,必须要预留一定的空间,为此rust提供了一些函数。

  • reserve():为字符串新增一些空间
  • shrink_to_fit():将字符串的容量缩小到它所包含的内容所需要的最小值。
  • shrink_to():将字符串的容量缩小到指定下限。如果当下容量小于下线,或者大于当前值,则什么也不做。
fn main(){
    let mut s = "micro cold".to_string();
    println!("original capacity = {}", s.capacity());
    s.reserve(10);
    println!("after reserve = {}", s.capacity());
    s.shrink_to_fit();
    println!("fit capacity = {}", s.capacity());
    s.shrink_to(25);
    println!("fit to 25 = {}", s.capacity());
}

//输出结果
original capacity = 10
after reserve = 20
fit capacity = 10
fit to 25 = 10

0x005 增删改查

String是可变字符串,所有提供了增加,删除,插入等操作

类别方法

弹出与追加        

追加字符push;追加字符串push_str;弹出最后一个字符pop
删除清空clear;截短truncate;删除某位置remove;匹配删除remove_matches
插入插入字符insert;插入字符串insert_str
替换匹配替换replace;位置替换replace_range;
匹配从左查找find;从右查找rfind;均返回第一个匹配的位置

上述方法进行测试:

fn main(){
    let mut s = "micro cold".to_string();

    s.push("a");
    println!("push("a") -> {}", s);
    
    s.push_str("bcd");
    println!("push_str("\bcd\") -> {}", s);
    
    s.truncate(10);
    println!("truncate(3) -> {}", s);
    
    s.remove(1);
    println!("remove(1) -> {}", s);

    s.insert(1, 'i');
    println!("insert(1, 'i') -> {}"), s);

    s.insert_str(0, "hello");
    println!("insert_str(0, \"hello\" -> {}", s);

    s.replace_range(0..5,"Hola");
    println!("replace_range(0..5, \"Hola\" -> {}", s);

    println!("s.replace(\"Hola\",\"你好\") -> {}", s.replace("Hola", "你好"));
}

//测试结果
push('a') -> micro colda
push_str("bcd") -> micro coldabcd
truncate(3) -> micro cold
remove(1) -> mcro cold
insert(1, 'i') -> micro cold
insert_str(0, "hello ") -> hello micro cold
replace_range(0..5, "Hola") -> Hola micro cold
s.replace("Hola", "你好") -> 你好 micro cold

0x006 字符串切片

字符串切片:指向String对象某个连续部分的引用。

切片的类型为:&str

使用形式:[starting_index..ending_index],其中,starting_index是切片起始位置的索引值,ending_index是切片终止位置的下一个位置的索引值。

注意:字符串字符串切片的范围索引必须发生在有效的UTF-8字符边界内,如果尝试从一个多字节中创建字符串切片,程序会报错并退出。

字符串字面量就是切片

let s = "Hello world";

变量s 的类型就是&str:它是一个指向二进制程序特定位置的切片。因为&str是一个不可变的引用,所有字符串字面量是不可变的。

fn main(){
    let s = String::from("hello world");
    
    let hello = &s[0..5];//如果要从索引0开始,可以不写两个点号之前的值 let hello =&s[..5];
    let world = &s[6..11];//如果slice包含String的最后一个字节,也可以舍弃尾部的数字 let world =&s[6..];

    println!("{},{}",hello, world)

    //也可以同时舍弃这两个值来获取整个字符串的slice
    let s1 = &s[..];
    //等价于
    let len = s.len()
    let s1 = &s[0..len];
}

0x007 String和str类型的转换

字符串字面量可以转换为String。相反,String也可以转换成str。

通过解引用操作实现。

impl Deref for String{
    fn deref(&self) -> &str{
        unsafe{ str::from_utf_unchecked(&self.vec) }
    }
}

利用解引用操作就可以将String转换成str:

let s: String = String::from("Hello");
let ss: &str = &s;

连接一个str字符串:

let s = String::from("Hello");
let b = ",world!";
let f = s +b; // f == "Hello,world!"

连接两个String对象,不能简单的直接相加。必须先通过解引用将后一个对象转换为&str才能进行连接:

let s = String::from("Hello");
let b = String::from(",world");
let f = s + &b; // f == "Hello,world"
//字符串连接之后,s的所有权发生了转移,而b的内容复制到了新的字符串中。

从String到str的转换是廉价的,相反,从str转换String需要分配新的内存。

当定义函数的参数时,&str会比String更加通用:因为此时既可以传递&str对象,也可以传递String对象。

字符串转整数

fn main(){
    let my_string = "27".to_string();
    let my_int = my_string.parse::<i32>().unwrap();
    println!("{:?}", my_string);
    println!("{:?}", my_int);
}

包含字符串

fn main(){
    let a = "abcd";
    println!("{:?}, a.contains("bc");
}

计算字节长度

fn main(){
    let s1 = "中国-China";
    println!("{:?}",s1.len()); //12
    let s2 = String::from("中国-China");
    println!("{:?}",s2.len()); //12
}

计算字符个数

fn main(){
    let s1 = "中国-China";
    println!("{:?}", s1.chars().count());  //8
    let s2 = String::from("中国-China");
    println!("{:?}", s2.chars().count()); //8

截取指定开始的n个的字符

fn substr(s: &str, start: usize, length: usize) -> String{
    s.chars().skip(start).take(length).collect()
}
fn main(){
    let s1 = "中国-China";//let s1 = String::from("中国-China");
    println!(":?}",substr(s1,1,100));
    println!({:?}",substr(s1,0,2));
}

获取指定位置开始的n个字节(如果存在非法的字符边界,则返回None)

fn main(){
    let mut s String::from("中国-China");
    println!("{:?}", s.get(0..=5)); //some("中国")
    println!("{:?}", s.get(0..=4)); //None
}

判断是不是以某个字符串结尾

fn main(){
    let s1 = "中国-China"; // let s1 = String::from("中国-China");
    assert_eq!(true, s1.ends_with("China"));
}

全部转为大写或小写

fn main(){
    let s1 = "中国-China"; // let s1 = String::from("中国-China");
    println!("{:?}",s1.to_uppercase()); //中国-CHINA

    //与to_uppercase()的不同
    let mut s2 = String::from("中国-China");
    s2.make_ascii_uppercase();
    println!("{:?}", s2); //中国-CHINA
}

//全部转换为小写

fn main(){
    let s1 = "中国-China"; // let s1 = String::from("中国-China");
    println!("{:?}",s1.to_lowercase()); //中国-china

    //与to_lowercase()的不同
    let mut s2 = String::from("中国-China");
    s2.make_ascii_lowercase();
    println!("{:?}", s2); //中国-china
}

判断是不是ASCII字符串

fn main(){
    let s1 = "中国-China";
    let s2 = "China';

    assert_eq!(false, s1.is_ascii());
    assert_eq!(true, s2.is_ascii());
}

判断指定位置是不一个合法的UTF-8边界,比如说汉字的UTF-8包含三个字节,那么第一个字节的结束位置必然不是一个合法的UTF-8边界(更准确的说,应该时这个位置是不是一个合法的字符的开始)

fn main(){
    let mut s1 = String::from("中国-China");
    assert_eq!(true, s1.is_char_boundary(0));
    assert_eq!(true, s1.is_char_boundary(12));
    assert_eq!(false, s1.is_char_boundary(2));
    assert_eq!(true, s1.is_char_boundary(3));
}

字符串替换

fn main(){
    let mut s = String::from("中国-China");
    println!("{:?}", s.replace("中国", "China");
}

字符串切割

fn main(){
    let mut s = String::from("中国-China');
    let result: Vec<&str> = s.split("-").collect();
    println!("{:?}", result); //["中国","China"]
}

//分离:s.split("separator")
//空白:s.split_whitespace()
//换行符:s.lines()

trim类有六个函数,trim、trim_left、trim_right、trim_matches、trim_left_matches、trim_right_matches

//trim
let s = "Hello\tword\t";
assert_eq!("Hello\tword\", s.trim());

//trim_left
let s = "Hello\tword\t";
assert_eq!("Hello\tword\", s.trim_left());

//trim_right
let s = "Hello\tword\t";
assert_eq!("Hello\tword\", s.trim_right());

//trim_matches
assert_eq!("11foolbar11".trim_matches('1'),"foolbar");
assert_eq!("123foolbar123".trim_matches(char::is_numeric), "foolbar");

let x: &[_] = &['1', '2'];
assert_eq!("12foolbar12".trim_matches(x), "foolbar");

//trim_left_matches
assert_eq!("11foolbar11".trim_letf_matches('1'),"foolbar11");
assert_eq!("123foolbar123".trim_left_matches(char::is_numeric), "foolbar123");

let x: &[_] = &['1', '2'];
assert_eq!("12foolbar12".trim_matches(x), "foolbar12");

assert_eq!("1fooX".trim_left_matches(|c| == '1' || c == 'X'), "fooX");

//trim_right_matches
assert_eq!("11foolbar11".trim_right_matches('1'),"11foolbar");
assert_eq!("123foolbar123".trim_right_matches(char::is_numeric), "123foolbar");

let x: &[_] = &['1', '2'];
assert_eq!("12foolbar12".trim_right_matches(x), "12foolbar");

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值