rust学习——操作字符串、字符串转义、操作UTF8-字符串 (操作中文字符串)

文章目录

  • 操作字符串
    • 追加 (Push)
    • 插入 (Insert)
    • 替换 (Replace)
        • 1、replace
        • 2、replacen
        • 3、replace_range
    • 删除 (Delete)
      • 1、 pop —— 删除并返回字符串的最后一个字符
      • 2、 remove —— 删除并返回字符串中指定位置的字符
      • 3、truncate —— 删除字符串中从指定位置开始到结尾的全部字符
      • 4、clear —— 清空字符串
    • 连接 (Concatenate)
  • 字符串转义
  • 操作 UTF-8 字符串
    • 字符
    • 字节
    • 获取子串

操作字符串

在这里插入图片描述

由于 String 是可变字符串,下面介绍 Rust 字符串的修改,添加,删除等常用方法:

追加 (Push)

在字符串尾部可以使用 push() 方法追加字符 char,也可以使用 push_str() 方法追加字符串字面量。这两个方法都是在原有的字符串上追加,并不会返回新的字符串。由于字符串追加操作要修改原来的字符串,则该字符串必须是可变的,即字符串变量必须由 mut 关键字修饰

示例代码如下:

fn main() {let mut s = String::from("Hello ");s.push_str("rust");println!("追加字符串 push_str() -> {}", s);s.push('!');println!("追加字符 push() -> {}", s);
}

代码运行结果:

追加字符串 push_str() -> Hello rust
追加字符 push() -> Hello rust!

插入 (Insert)

在这里插入图片描述

可以使用 insert() 方法插入单个字符 char,也可以使用 insert_str() 方法插入字符串字面量,与 push() 方法不同,这俩方法需要传入两个参数,第一个参数是字符(串)插入位置的索引,第二个参数是要插入的字符(串),索引从 0 开始计数,如果越界则会发生错误。由于字符串插入操作要修改原来的字符串,则该字符串必须是可变的,即字符串变量必须由 mut 关键字修饰

示例代码如下:

fn main() {let mut s = String::from("Hello rust!");s.insert(5, ',');println!("插入字符 insert() -> {}", s);s.insert_str(6, " I like");println!("插入字符串 insert_str() -> {}", s);
}

代码运行结果:

插入字符 insert() -> Hello, rust!
插入字符串 insert_str() -> Hello, I like rust!

替换 (Replace)

在这里插入图片描述

如果想要把字符串中的某个字符串替换成其它的字符串,那可以使用 replace() 方法。与替换有关的方法有三个。

1、replace

该方法可适用于 String&str 类型。replace() 方法接收两个参数,第一个参数是要被替换的字符串,第二个参数是新的字符串。该方法会替换所有匹配到的字符串。该方法是返回一个新的字符串,而不是操作原来的字符串

示例代码如下:

fn main() {let string_replace = String::from("I like rust. Learning rust is my favorite!");let new_string_replace = string_replace.replace("rust", "RUST");dbg!(new_string_replace);
}

代码运行结果:

new_string_replace = "I like RUST. Learning RUST is my favorite!"
2、replacen

该方法可适用于 String&str 类型。replacen() 方法接收三个参数,前两个参数与 replace() 方法一样,第三个参数则表示替换的个数。该方法是返回一个新的字符串,而不是操作原来的字符串

示例代码如下:

fn main() {let string_replace = "I like rust. Learning rust is my favorite!";let new_string_replacen = string_replace.replacen("rust", "RUST", 1);dbg!(new_string_replacen);
}

代码运行结果:

new_string_replacen = "I like RUST. Learning rust is my favorite!"
3、replace_range

该方法仅适用于 String 类型。replace_range 接收两个参数,第一个参数是要替换字符串的范围(Range),第二个参数是新的字符串。该方法是直接操作原来的字符串,不会返回新的字符串。该方法需要使用 mut 关键字修饰

示例代码如下:

fn main() {let mut string_replace_range = String::from("I like rust!");string_replace_range.replace_range(7..8, "R");dbg!(string_replace_range);
}

代码运行结果:

string_replace_range = "I like Rust!"

删除 (Delete)

在这里插入图片描述

与字符串删除相关的方法有 4 个,他们分别是 pop()remove()truncate()clear()。这四个方法仅适用于 String 类型。

1、 pop —— 删除并返回字符串的最后一个字符

该方法是直接操作原来的字符串。但是存在返回值,其返回值是一个 Option 类型,如果字符串为空,则返回 None。 示例代码如下:

fn main() {let mut string_pop = String::from("rust pop 中文!");let p1 = string_pop.pop();let p2 = string_pop.pop();dbg!(p1);dbg!(p2);dbg!(string_pop);
}

代码运行结果:

p1 = Some('!',
)
p2 = Some('文',
)
string_pop = "rust pop 中"

2、 remove —— 删除并返回字符串中指定位置的字符

该方法是直接操作原来的字符串。但是存在返回值,其返回值是删除位置的字符串,只接收一个参数,表示该字符起始索引位置。remove() 方法是按照字节来处理字符串的,如果参数所给的位置不是合法的字符边界,则会发生错误。

示例代码如下:

fn main() {let mut string_remove = String::from("测试remove方法");println!("string_remove 占 {} 个字节",std::mem::size_of_val(string_remove.as_str()));// 删除第一个汉字string_remove.remove(0);// 下面代码会发生错误// string_remove.remove(1);// 直接删除第二个汉字// string_remove.remove(3);dbg!(string_remove);
}

代码运行结果:

string_remove 占 18 个字节
string_remove = "试remove方法"

3、truncate —— 删除字符串中从指定位置开始到结尾的全部字符

该方法是直接操作原来的字符串。无返回值。该方法 truncate() 方法是按照字节来处理字符串的,如果参数所给的位置不是合法的字符边界,则会发生错误。

示例代码如下:

fn main() {let mut string_truncate = String::from("测试truncate");string_truncate.truncate(3);dbg!(string_truncate);
}

代码运行结果:

string_truncate = "测"

4、clear —— 清空字符串

该方法是直接操作原来的字符串。调用后,删除字符串中的所有字符,相当于 truncate() 方法参数为 0 的时候。

示例代码如下:

fn main() {let mut string_clear = String::from("string clear");string_clear.clear();dbg!(string_clear);
}

代码运行结果:

string_clear = ""

连接 (Concatenate)

在这里插入图片描述

1、使用 + 或者 += 连接字符串

使用 + 或者 += 连接字符串,要求右边的参数必须为字符串的切片引用(Slice)类型。其实当调用 + 的操作符时,相当于调用了 std::string 标准库中的 add() 方法,这里 add() 方法的第二个参数是一个引用的类型。因此我们在使用 +, 必须传递切片引用类型。不能直接传递 String 类型。+ 是返回一个新的字符串,所以变量声明可以不需要 mut 关键字修饰

示例代码如下:

fn main() {let string_append = String::from("hello ");let string_rust = String::from("rust");// &string_rust会自动解引用为&strlet result = string_append + &string_rust;let mut result = result + "!"; // `result + "!"` 中的 `result` 是不可变的result += "!!!";println!("连接字符串 + -> {}", result);
}

代码运行结果:

连接字符串 + -> hello rust!!!!

add() 方法的定义:

fn add(self, s: &str) -> String

因为该方法涉及到更复杂的特征功能,因此我们这里简单说明下:

fn main() {let s1 = String::from("hello,");let s2 = String::from("world!");// 在下句中,s1的所有权被转移走了,因此后面不能再使用s1let s3 = s1 + &s2;assert_eq!(s3,"hello,world!");// 下面的语句如果去掉注释,就会报错// println!("{}",s1);
}

selfString 类型的字符串 s1,该函数说明,只能将 &str 类型的字符串切片添加到 String 类型的 s1 上,然后返回一个新的 String 类型,所以 let s3 = s1 + &s2; 就很好解释了,将 String 类型的 s1&str 类型的 s2 进行相加,最终得到 String 类型的 s3

由此可推,以下代码也是合法的:

let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");// String = String + &str + &str + &str + &str
let s = s1 + "-" + &s2 + "-" + &s3;

String + &str返回一个 String,然后再继续跟一个 &str 进行 + 操作,返回一个 String 类型,不断循环,最终生成一个 s,也是 String 类型。

s1 这个变量通过调用 add() 方法后,所有权被转移到 add() 方法里面, add() 方法调用后就被释放了,同时 s1 也被释放了。再使用 s1 就会发生错误。这里涉及到所有权转移(Move)的相关知识。

2、使用 format! 连接字符串

format! 这种方式适用于 String&strformat! 的用法与 print! 的用法类似,详见格式化输出。

示例代码如下:

fn main() {let s1 = "hello";let s2 = String::from("rust");let s = format!("{} {}!", s1, s2);println!("{}", s);
}

代码运行结果:

hello rust!

字符串转义

我们可以通过转义的方式 \ 输出 ASCII 和 Unicode 字符。

fn main() {// 通过 \ + 字符的十六进制表示,转义输出一个字符let byte_escape = "I'm writing \x52\x75\x73\x74!";println!("What are you doing\x3F (\\x3F means ?) {}", byte_escape);// \u 可以输出一个 unicode 字符let unicode_codepoint = "\u{211D}";let character_name = "\"DOUBLE-STRUCK CAPITAL R\"";println!("Unicode character {} (U+211D) is called {}",unicode_codepoint, character_name);// 换行了也会保持之前的字符串格式// 使用\忽略换行符let long_string = "String literalscan span multiple lines.The linebreak and indentation here ->\<- can be escaped too!";println!("{}", long_string);
}

输出

What are you doing? (\x3F means ?) I'm writing Rust!
Unicode character ℝ (U+211D) is called "DOUBLE-STRUCK CAPITAL R"
String literalscan span multiple lines.The linebreak and indentation here -><- can be escaped too!

当然,在某些情况下,可能你会希望保持字符串的原样,不要转义:

fn main() {println!("{}", "hello \\x52\\x75\\x73\\x74");let raw_str = r"Escapes don't work here: \x3F \u{211D}";println!("{}", raw_str);// 如果字符串包含双引号,可以在开头和结尾加 #let quotes = r#"And then I said: "There is no escape!""#;println!("{}", quotes);// 如果还是有歧义,可以继续增加,没有限制let longer_delimiter = r###"A string with "# in it. And even "##!"###;println!("{}", longer_delimiter);
}

输出

hello \x52\x75\x73\x74
Escapes don't work here: \x3F \u{211D}
And then I said: "There is no escape!"
A string with "# in it. And even "##!

操作 UTF-8 字符串

前文提到了几种使用 UTF-8 字符串的方式,下面来一一说明。

字符

如果你想要以 Unicode 字符的方式遍历字符串,最好的办法是使用 chars 方法,例如:

for c in "中国人".chars() {println!("{}", c);
}

输出如下

中
国
人

字节

这种方式是返回字符串的底层字节数组表现形式:

for b in "中国人".bytes() {println!("{}", b);
}

输出如下:

228
184
173
229
155
189
228
186
186

获取子串

想要准确的从 UTF-8 字符串中获取子串是较为复杂的事情,例如想要从 holla中国人नमस्ते 这种变长的字符串中取出某一个子串,使用标准库你是做不到的。 你需要在 crates.io 上搜索 utf8 来寻找想要的功能。

可以考虑尝试下这个库:utf8_slice。

use utf8_slice;
fn main() {let s = "The 🚀 goes to the 🌑!";let rocket = utf8_slice::slice(s, 4, 5);// 结果是 "🚀"
}

练习题
练习题答案

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/117745.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【尘缘赠书活动:01期】Python数据挖掘——入门进阶与实用案例分析

引言 本案例将根据已收集到的电力数据&#xff0c;深度挖掘各电力设备的电流、电压和功率等情况&#xff0c;分析各电力设备的实际用电量&#xff0c;进而为电力公司制定电能能源策略提供一定的参考依据。更多详细内容请参考**《Python数据挖掘&#xff1a;入门进阶与实用案例…

CSS设置超出范围滚动条和滚动条样式

CSS设置超出范围滚动条和滚动条样式 效果展示 当块级内容区域超出块级元素范围的时候&#xff0c;就会以滚动条的形式展示&#xff0c;你可以滚动里面的内容&#xff0c;里面的内容不会超出块级区域范围。 未设置超出隐藏&#xff0c;显示滚动条 超出隐藏&#xff0c;显示滚动…

财报解读:双轮驱动下,香飘飘究竟能打开多大的获利空间?

2023年以来&#xff0c;食品饮料行业稳中求进&#xff0c;消费市场情绪逐步上扬。 数据显示&#xff0c;2023年上半年&#xff0c;食品饮料行业实现营收5338.86亿元&#xff0c;同比增长9.65%&#xff1b;归母净利润1125.03亿元&#xff0c;同比增长14.93%&#xff0c;营收和归…

开源博客项目Blog .NET Core源码学习(4:生成验证码)

开源博客项目Blog中的后台管理登录界面中支持输入验证码&#xff08;如下图所示&#xff09;&#xff0c;本文学习并记录项目中验证码的生成及调用方式。   博客项目中调用VerifyCode类生成验证码&#xff0c;该类位于App.Framwork项目中&#xff0c;命名空间为App.Framwork…

python实验13_科学计算

实验13&#xff1a;科学计算 文章目录 实验13&#xff1a;科学计算1.实验目标及要求2. 实验主要内容3. 心得体会 1.实验目标及要求 &#xff08;1&#xff09;掌握numpy库的常用方法。 &#xff08;2&#xff09;掌握使用matplotlib库的常用方法。 2. 实验主要内容 ① 利用…

云原生之深入解析如何合并多个kubeconfig文件

项目通常有多个 k8s 集群环境&#xff0c;dev、testing、staging、prod&#xff0c;kubetcl 在多个环境中切换&#xff0c;操作集群 Pod 等资源对象&#xff0c;前提条件是将这三个环境的配置信息都写到本地机的 $HOME/.kube/config 文件中。默认情况下kubectl会查找$HOME/.kub…

解析外贸开发信的结构?营销邮件书写技巧?

做外贸的开发信结构是怎样的&#xff1f;写外贸邮件的注意事项&#xff1f; 外贸开发信是国际贸易中至关重要的一环&#xff0c;它不仅是与潜在客户建立联系的第一步&#xff0c;也是一种有效的市场推广工具。蜂邮EDM将深入解析外贸开发信的结构&#xff0c;帮助您更好地理解如…

vue2技能树(9)-prop属性,自定义事件

目录 Vue 2 中的 Prop 详解基本用法项目示例 动态Props项目示例 Prop 验证项目示例 单向数据流项目示例 Vue 2 自定义事件详解自定义事件的基本使用项目示例 传递数据项目示例 命名自定义事件项目示例 &#x1f44d; 点赞&#xff0c;你的认可是我创作的动力&#xff01; ⭐️…

Java如何实现单点登录(SSO):基于JWT和Redis的实例详解

前言 单点登录&#xff08;Single Sign-On&#xff0c;简称SSO&#xff09;是一种身份验证和访问控制机制&#xff0c;允许用户使用一组凭证&#xff08;如登录名和密码&#xff09;登录到多个应用程序中&#xff0c;而无需为每个应用程序单独进行身份验证。用户只需要登录一次…

c语言进制的转换10进制转换16进制

c语言进制的转换10进制转换16进制 c语言的进制的转换 c语言进制的转换10进制转换16进制一、16进制的介绍二、10进制转换16进制的方法 一、16进制的介绍 十六进制&#xff1a; 十六进制逢十六进一&#xff0c;所有的数组是0到9和A到F组成&#xff0c;其中A代表10&#xff0c;B代…

简化通知基础设施:开源的消息通知服务 | 开源专题 No.41

novuhq/novu Stars: 22.9k License: MIT Novu 是一个开源的通知基础设施项目&#xff0c;它提供了统一的 API 来通过多个渠道发送通知&#xff0c;包括应用内、推送、电子邮件、短信和聊天。主要功能有&#xff1a; 为所有消息提供商 (应用内、电子邮件、短信、推送和聊天) 提…

Spring Boot和XXL-Job:高效定时任务管理

Spring Boot和XXL-Job&#xff1a;高效定时任务管理 前言第一&#xff1a;XXL-Job简介什么是XXL-job对比别的任务调度 第二&#xff1a; springboot整合XXL-job配置XXL-Job Admin拉取XXL-Job代码修改拉取的配置 配置执行器自己的项目如何整合maven依赖properties文件配置执行器…

mysql基础、索引及sql优化

mysql数据库 数据库基础知识 为什么要使用数据库 数据存内存&#xff1b;优点&#xff1a;存取速度快。缺点&#xff1a;数据不能永久保存 数据存文件。优点&#xff1a;数据永久存储。缺点&#xff1a;速度比内存操作慢&#xff0c;频繁i…

使用jdbc技术连接数据库

连接数据库 <dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version><scope>compile</scope></dependency> </dependencies> g…

教师必备宝藏,强烈推荐

亲爱的教师朋友们&#xff0c;你们是不是在为学期末成绩查询而头疼呢&#xff1f;一学期下来&#xff0c;成堆的试卷和成绩单&#xff0c;还有学生家长的各种咨询&#xff0c;让人应接不暇。现在&#xff0c;我给你们分享一个教师必备的宝藏&#xff0c;让你们的成绩查询工作变…

AtCoder ABC 138

C - Alchemist 排序贪心&#xff0c;小的应该先除&#xff0c;大的后除 D - Ki 搜索 pypy不出意外的挂了 // atcoder.cpp : // #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <map> #include <set> #include <cstring> #include <…

games101作业七,计算机图形学作业三,详细知识点总结(附代码)

计算机图形学课程作业总结&#xff0c;同课程慎重Ctrl C/V 文章目录 1. 光线追踪算法光线追踪的准备工作Mller-Trumbore算法rayTriangleIntersect()函数 2. 光线追踪包围盒加速算法1. AABB 包围盒又称 轴对齐包围盒2. 光线与包围盒&#xff08;AABB&#xff09;的相交检测算法3…

从JVM方面解释java传递问题

前言&#xff1a; Java传递问题&#xff0c;网上解释的比较多&#xff0c;大多是从代码和传递的规范的层次来解释。前段时间&#xff0c;自己也一直在思考这个问题&#xff0c;大部分的解释让我很难印象深刻&#xff0c;经常忘&#xff0c;刚好看过一点jvm方面的书&#xff0c…

对GRUB和initramfs的小探究

竞赛时对操作系统启动过程产生了些疑问&#xff0c;于是问题导向地浅浅探究了下GRUB和initramfs相关机制&#xff0c;相关笔记先放在这里了。 内核启动流程 在传统的BIOS系统中&#xff0c;计算机具体的启动流程如下&#xff1a; 电源启动&#xff1a;当计算机的电源打开时&…

『heqingchun-Qt的艺术-优雅界面设计开发』

Qt的艺术-优雅界面设计开发 效果图 一、新建Qt窗口工程 二、准备资源文件 1.图标资源 链接: 图标资源 2.Qss资源 链接: Qss资源 三、设计开发 项目源码链接: CSDN资源