Rust字符串实用函数的使用指南
2022-10-184.4k 阅读
Rust字符串基础概念
在Rust中,字符串相关类型主要有&str
和String
。&str
是字符串切片,它是一个指向UTF - 8编码字符串数据的不可变引用,通常以字面量形式出现,例如let s: &str = "hello";
。String
则是一个可增长、可改变的字符串类型,它拥有数据的所有权,例如let mut s = String::from("world");
。
字符串创建函数
String::from
- 本质:这是一个从字符串字面量创建
String
类型的方法。它会把字符串字面量的数据复制到新分配的String
对象中。 - 代码示例:
- 本质:这是一个从字符串字面量创建
let s = String::from("hello");
println!("The string is: {}", s);
String::new
- 本质:创建一个新的空
String
。后续可以通过其他方法向这个空字符串中添加内容。 - 代码示例:
- 本质:创建一个新的空
let mut s = String::new();
s.push('a');
println!("The string is: {}", s);
format!
宏- 本质:类似于C语言中的
printf
函数,它允许根据格式化字符串和参数创建一个新的String
。它会分配新的内存来存储格式化后的字符串。 - 代码示例:
- 本质:类似于C语言中的
let num = 42;
let s = format!("The number is {}", num);
println!("The string is: {}", s);
字符串拼接函数
push
- 本质:用于向
String
类型的字符串末尾添加一个字符。它修改了调用它的String
对象本身。 - 代码示例:
- 本质:用于向
let mut s = String::from("hel");
s.push('l');
s.push('o');
println!("The string is: {}", s);
push_str
- 本质:将一个字符串切片追加到
String
的末尾。与push
不同,它接受的是一个字符串切片(&str
),并且同样修改调用它的String
对象。 - 代码示例:
- 本质:将一个字符串切片追加到
let mut s1 = String::from("Hello");
let s2 = " World";
s1.push_str(s2);
println!("The string is: {}", s1);
+
运算符- 本质:用于连接两个
String
。它会把右侧的String
移动到左侧的String
后面,并返回结果String
。在连接过程中,左侧的String
会被消耗掉。 - 代码示例:
- 本质:用于连接两个
let s1 = String::from("Hello");
let s2 = String::from(" World");
let s3 = s1 + &s2;
// 这里s1已经不能再使用,因为它被移动到了s3中
println!("The string is: {}", s3);
format!
宏拼接- 本质:通过
format!
宏,可以在格式化字符串中包含多个变量和字符串,从而实现拼接效果。与+
运算符不同,它不会消耗任何原有的String
对象。 - 代码示例:
- 本质:通过
let s1 = String::from("Hello");
let s2 = String::from(" World");
let s3 = format!("{}{}", s1, s2);
// s1和s2仍然可以继续使用
println!("The string is: {}", s3);
字符串长度相关函数
len
- 本质:返回字符串的字节长度。需要注意的是,由于Rust字符串是UTF - 8编码,一个字符可能占用多个字节,所以
len
返回的不是字符个数。 - 代码示例:
- 本质:返回字符串的字节长度。需要注意的是,由于Rust字符串是UTF - 8编码,一个字符可能占用多个字节,所以
let s = String::from("Hello");
println!("The length of the string is: {}", s.len());
chars
和count
- 本质:
chars
方法将字符串拆分成一个个字符的迭代器,count
方法用于统计迭代器中的元素个数。结合这两个方法可以得到字符串的字符个数。 - 代码示例:
- 本质:
let s = String::from("你好");
let char_count = s.chars().count();
println!("The character count of the string is: {}", char_count);
字符串查找函数
contains
- 本质:检查字符串是否包含指定的子字符串。它会从字符串的开头开始搜索,直到找到匹配的子字符串或者到达字符串末尾。
- 代码示例:
let s = String::from("Hello, world!");
let contains_substring = s.contains("world");
println!("Does the string contain 'world'? {}", contains_substring);
starts_with
- 本质:判断字符串是否以指定的子字符串开头。
- 代码示例:
let s = String::from("Hello, world!");
let starts_with_hello = s.starts_with("Hello");
println!("Does the string start with 'Hello'? {}", starts_with_hello);
ends_with
- 本质:判断字符串是否以指定的子字符串结尾。
- 代码示例:
let s = String::from("Hello, world!");
let ends_with_world = s.ends_with("world!");
println!("Does the string end with 'world!'? {}", ends_with_world);
find
- 本质:查找指定子字符串在字符串中的第一次出现位置,并返回其索引。如果未找到,则返回
None
。 - 代码示例:
- 本质:查找指定子字符串在字符串中的第一次出现位置,并返回其索引。如果未找到,则返回
let s = String::from("Hello, world!");
if let Some(index) = s.find("world") {
println!("The index of 'world' is: {}", index);
} else {
println!("'world' not found.");
}
rfind
- 本质:与
find
类似,但它是从字符串的末尾开始查找指定子字符串的最后一次出现位置,并返回其索引。如果未找到,则返回None
。 - 代码示例:
- 本质:与
let s = String::from("banana");
if let Some(index) = s.rfind("na") {
println!("The index of the last 'na' is: {}", index);
} else {
println!("'na' not found.");
}
字符串替换函数
replace
- 本质:将字符串中所有匹配的子字符串替换为指定的新字符串。它会创建一个新的
String
对象,原字符串保持不变。 - 代码示例:
- 本质:将字符串中所有匹配的子字符串替换为指定的新字符串。它会创建一个新的
let s = String::from("Hello, world!");
let new_s = s.replace("world", "Rust");
println!("The new string is: {}", new_s);
replacen
- 本质:与
replace
类似,但它可以指定替换的次数。同样会创建一个新的String
对象。 - 代码示例:
- 本质:与
let s = String::from("banana");
let new_s = s.replacen("na", "XY", 1);
println!("The new string is: {}", new_s);
字符串分割函数
split
- 本质:以指定的分隔符将字符串分割成多个子字符串,并返回一个迭代器。每个子字符串不包含分隔符。
- 代码示例:
let s = String::from("Hello,world,Rust");
for part in s.split(',') {
println!("Part: {}", part);
}
splitn
- 本质:与
split
类似,但它可以指定最多分割的次数。返回的迭代器会包含分割后的子字符串。 - 代码示例:
- 本质:与
let s = String::from("a,b,c,d");
let parts: Vec<&str> = s.splitn(3, ',').collect();
for part in parts {
println!("Part: {}", part);
}
rsplit
- 本质:从字符串的末尾开始,以指定的分隔符将字符串分割成多个子字符串,并返回一个迭代器。
- 代码示例:
let s = String::from("Hello,world,Rust");
for part in s.rsplit(',') {
println!("Part: {}", part);
}
rsplitn
- 本质:从字符串的末尾开始,最多分割指定次数,并返回一个迭代器。
- 代码示例:
let s = String::from("a,b,c,d");
let parts: Vec<&str> = s.rsplitn(3, ',').collect();
for part in parts {
println!("Part: {}", part);
}
split_once
- 本质:以指定的分隔符将字符串分割一次,返回一个包含两个元素的元组,第一个元素是分隔符左边的部分,第二个元素是分隔符右边的部分。如果未找到分隔符,则返回
None
。 - 代码示例:
- 本质:以指定的分隔符将字符串分割一次,返回一个包含两个元素的元组,第一个元素是分隔符左边的部分,第二个元素是分隔符右边的部分。如果未找到分隔符,则返回
let s = String::from("Hello,world");
if let Some((left, right)) = s.split_once(',') {
println!("Left: {}, Right: {}", left, right);
} else {
println!("Separator not found.");
}
rsplit_once
- 本质:从字符串的末尾开始,以指定的分隔符将字符串分割一次,返回一个包含两个元素的元组。如果未找到分隔符,则返回
None
。 - 代码示例:
- 本质:从字符串的末尾开始,以指定的分隔符将字符串分割一次,返回一个包含两个元素的元组。如果未找到分隔符,则返回
let s = String::from("Hello,world");
if let Some((left, right)) = s.rsplit_once(',') {
println!("Left: {}, Right: {}", left, right);
} else {
println!("Separator not found.");
}
字符串转换函数
to_lowercase
- 本质:将字符串中的所有字符转换为小写形式,并返回一个新的
String
。原字符串保持不变。 - 代码示例:
- 本质:将字符串中的所有字符转换为小写形式,并返回一个新的
let s = String::from("HELLO");
let lower_s = s.to_lowercase();
println!("The lowercase string is: {}", lower_s);
to_uppercase
- 本质:将字符串中的所有字符转换为大写形式,并返回一个新的
String
。原字符串保持不变。 - 代码示例:
- 本质:将字符串中的所有字符转换为大写形式,并返回一个新的
let s = String::from("hello");
let upper_s = s.to_uppercase();
println!("The uppercase string is: {}", upper_s);
parse
- 本质:将字符串解析为其他类型,例如
i32
、f64
等。如果解析失败,会返回一个Err
值。 - 代码示例:
- 本质:将字符串解析为其他类型,例如
let s = String::from("42");
if let Ok(num) = s.parse::<i32>() {
println!("The parsed number is: {}", num);
} else {
println!("Failed to parse.");
}
to_string
- 本质:将实现了
Display
trait的类型转换为String
。例如,整数、浮点数等都可以通过to_string
方法转换为字符串。 - 代码示例:
- 本质:将实现了
let num = 42;
let s = num.to_string();
println!("The string is: {}", s);
字符串修剪函数
trim
- 本质:去除字符串两端的空白字符(空格、制表符、换行符等),并返回一个新的字符串切片(
&str
)。原字符串保持不变。 - 代码示例:
- 本质:去除字符串两端的空白字符(空格、制表符、换行符等),并返回一个新的字符串切片(
let s = String::from(" Hello ");
let trimmed_s = s.trim();
println!("The trimmed string is: '{}'", trimmed_s);
trim_start
- 本质:去除字符串开头的空白字符,并返回一个新的字符串切片(
&str
)。 - 代码示例:
- 本质:去除字符串开头的空白字符,并返回一个新的字符串切片(
let s = String::from(" Hello ");
let trimmed_s = s.trim_start();
println!("The trimmed string is: '{}'", trimmed_s);
trim_end
- 本质:去除字符串末尾的空白字符,并返回一个新的字符串切片(
&str
)。 - 代码示例:
- 本质:去除字符串末尾的空白字符,并返回一个新的字符串切片(
let s = String::from(" Hello ");
let trimmed_s = s.trim_end();
println!("The trimmed string is: '{}'", trimmed_s);
trim_matches
- 本质:去除字符串两端所有匹配指定字符的字符,并返回一个新的字符串切片(
&str
)。 - 代码示例:
- 本质:去除字符串两端所有匹配指定字符的字符,并返回一个新的字符串切片(
let s = String::from("***Hello***");
let trimmed_s = s.trim_matches('*');
println!("The trimmed string is: '{}'", trimmed_s);
trim_start_matches
- 本质:去除字符串开头所有匹配指定字符的字符,并返回一个新的字符串切片(
&str
)。 - 代码示例:
- 本质:去除字符串开头所有匹配指定字符的字符,并返回一个新的字符串切片(
let s = String::from("***Hello***");
let trimmed_s = s.trim_start_matches('*');
println!("The trimmed string is: '{}'", trimmed_s);
trim_end_matches
- 本质:去除字符串末尾所有匹配指定字符的字符,并返回一个新的字符串切片(
&str
)。 - 代码示例:
- 本质:去除字符串末尾所有匹配指定字符的字符,并返回一个新的字符串切片(
let s = String::from("***Hello***");
let trimmed_s = s.trim_end_matches('*');
println!("The trimmed string is: '{}'", trimmed_s);
字符串比较函数
eq
- 本质:比较两个字符串是否相等。它会逐个字符地比较字符串内容,区分大小写。
- 代码示例:
let s1 = String::from("Hello");
let s2 = String::from("Hello");
let is_equal = s1.eq(&s2);
println!("Are the strings equal? {}", is_equal);
cmp
- 本质:按照字典序比较两个字符串。它返回一个
Ordering
枚举值,表示比较结果(小于、等于、大于)。 - 代码示例:
- 本质:按照字典序比较两个字符串。它返回一个
let s1 = String::from("apple");
let s2 = String::from("banana");
let result = s1.cmp(&s2);
match result {
std::cmp::Ordering::Less => println!("s1 is less than s2"),
std::cmp::Ordering::Equal => println!("s1 is equal to s2"),
std::cmp::Ordering::Greater => println!("s1 is greater than s2"),
}
starts_with
和ends_with
用于比较开头和结尾- 本质:这两个函数在前面查找部分已经介绍过,但它们也可以看作是一种特殊的比较。
starts_with
比较字符串开头部分是否匹配,ends_with
比较字符串结尾部分是否匹配。 - 代码示例:
- 本质:这两个函数在前面查找部分已经介绍过,但它们也可以看作是一种特殊的比较。
let s = String::from("Hello, world!");
let starts_with_hello = s.starts_with("Hello");
let ends_with_world = s.ends_with("world!");
println!("Starts with 'Hello': {}", starts_with_hello);
println!("Ends with 'world!': {}", ends_with_world);
字符串迭代函数
chars
- 本质:将字符串拆分成一个个字符的迭代器。通过这个迭代器可以方便地遍历字符串中的每个字符。
- 代码示例:
let s = String::from("Hello");
for c in s.chars() {
println!("Character: {}", c);
}
bytes
- 本质:将字符串拆分成一个个字节的迭代器。由于Rust字符串是UTF - 8编码,通过这个迭代器可以访问字符串的底层字节表示。
- 代码示例:
let s = String::from("Hello");
for byte in s.bytes() {
println!("Byte: {}", byte);
}
lines
- 本质:将字符串按行分割,并返回一个迭代器,每个元素是一行字符串(不包含换行符)。这在处理多行文本时非常有用。
- 代码示例:
let s = String::from("Line 1\nLine 2\nLine 3");
for line in s.lines() {
println!("Line: {}", line);
}
字符串格式化函数
format_args!
系列宏- 本质:
format_args!
、write!
、writeln!
等宏用于更灵活的字符串格式化。format_args!
创建一个Arguments
结构体,包含格式化信息;write!
和writeln!
将格式化后的内容写入实现了Write
trait的对象(如String
)。 - 代码示例:
- 本质:
use std::fmt::Write;
let mut s = String::new();
let num = 42;
write!(&mut s, "The number is {}", num).unwrap();
println!("The string is: {}", s);
format!
宏的高级格式化- 本质:
format!
宏支持各种格式化选项,如指定宽度、精度等。例如,格式化浮点数时可以指定小数位数。 - 代码示例:
- 本质:
let num = 3.1415926;
let s = format!("The number with 2 decimal places is: {:.2}", num);
println!("The string is: {}", s);
字符串内存管理相关函数
into_bytes
- 本质:将
String
转换为Vec<u8>
,获取字符串的字节表示,并消耗掉原String
对象。 - 代码示例:
- 本质:将
let s = String::from("Hello");
let bytes = s.into_bytes();
for byte in bytes {
println!("Byte: {}", byte);
}
from_utf8
和from_utf8_lossy
- 本质:
from_utf8
尝试将Vec<u8>
转换为Result<String>
,如果字节序列是有效的UTF - 8编码,则返回Ok(String)
,否则返回Err
。from_utf8_lossy
则是一种“宽容”的转换,它会将无效的UTF - 8字节序列替换为�
(Unicode替换字符),并返回一个Cow<'a, str>
类型,可能是借用的字符串切片(如果输入是有效的UTF - 8),也可能是新分配的String
。 - 代码示例:
- 本质:
let valid_bytes = b"Hello".to_vec();
if let Ok(s) = String::from_utf8(valid_bytes) {
println!("The string is: {}", s);
} else {
println!("Invalid UTF - 8");
}
let invalid_bytes = vec![65, 66, 255, 68];
let s = std::str::from_utf8_lossy(&invalid_bytes);
println!("The string is: {}", s);
通过深入理解和灵活运用这些Rust字符串实用函数,开发者能够更加高效地处理字符串相关的操作,无论是在简单的文本处理还是复杂的应用开发中,都能充分发挥Rust语言在字符串处理方面的强大能力。