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

news2024/10/2 10:37:49

文章目录

  • 操作字符串
    • 追加 (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会自动解引用为&str
    let 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的所有权被转移走了,因此后面不能再使用s1
    let 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 literals
                        can 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 literals
                        can 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.coloradmin.cn/o/1128792.html

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

相关文章

CentOS7单磁盘挂载一个目录

1、查看磁盘是否存在 fdisk -l 2、格式化磁盘 mkfs -t ext4 /dev/vdb 3、查看磁盘分区的UUID blkid /dev/vdb 4、创建挂载目录 mkdir -p /data 5、磁盘挂载 mount /dev/vdb /data 6、设置开机启动自动挂载 需要让系统开机自动挂载&#xff0c;需要将挂载信息写入到/etc/f…

安装PyCharm必看,手把手教你安装pycharm

目录 一&#xff0c;简介 二&#xff0c;安装包 一&#xff0c;简介 Jetbrains家族和Pycharm版本划分&#xff1a; pycharm是Jetbrains家族中的一个明星产品&#xff0c;Jetbrains开发了许多好用的编辑器&#xff0c;包括Java编辑器&#xff08;IntelliJ IDEA&#xff09;、…

超实用!你不得不知道的7款项目管理神器

大家好&#xff0c;我是老原。 一个项目无论大小&#xff0c;都需要一款高效且实用的项目管理工具&#xff0c;对项目流程进行把控、及时共享工作文档&#xff0c;从而让工作变得更有效率。 大家在网上搜到的就有很多&#xff0c;譬如project、禅道、甘特图等这些都是使用率超…

“深入探讨Java JUC中的ReentrantLock锁:实现多线程同步与并发控制“

简介 1、从Java5开始&#xff0c;Java提供了一种功能更强大的线程同步机制——通过显式定义同步锁对象来实现同步&#xff0c;在这种机制下&#xff0c;同步锁由Lock对象充当。 2、Lock 提供了比synchronized方法和synchronized代码块更广泛的锁定操作&#xff0c;Lock允许实…

YOLOv8优化:独家创新(Partial_C_Detect)检测头结构创新,实现涨点 | 检测头新颖创新系列

💡💡💡本文独家改进:独家创新(Partial_C_Detect)检测头结构创新,适合科研创新度十足,强烈推荐 Partial_C_Detect | 亲测在多个数据集能够实现大幅涨点 💡💡💡Yolov8魔术师,独家首发创新(原创),适用于Yolov5、Yolov7、Yolov8等各个Yolo系列,专栏文章提…

ES 8.x 向量检索性能测试 把向量检索性能提升100倍!

向量检索不仅在的跨模态检索场景中应用广泛&#xff0c;随着chat gpt的或者&#xff0c;利用es的向量检索&#xff0c;在Ai领域发挥着越来越大的作用。 本文&#xff0c;主要测试es的向量检索性能。我从8.x就开始关注ES的向量检索了。当前ES已经发布到 8.10 版本。以下是官方文…

微信小程序商城制作教程

在这个数字化快速发展的时代&#xff0c;微信小程序商城已经成为越来越多商家的首选。搭建微信小程序商城不仅能够拓宽销售渠道&#xff0c;还能增加品牌曝光度和用户粘性。本文将指导你如何搭建微信小程序商城&#xff0c;从登录乔拓云网后台到发布上线全流程介绍。 1. 登录乔…

【0229】libpq库实现压测PG服务器max_connections的最大连接数

1. PG服务器接收的最大连接数 在PG服务的postgresql.conf配置文件中,参数:max_connections 注明了PG服务所能够接受的最大客户端的连接数量。此值默认是100,那么PG服务此参数最大能够调到多大呢? 本文将采用libpq库编写demo来进行压测,并将最终的结论和数据于文章中给出。…

Redis过期处理策略、惰性删除、定期删除、RDB和AOF、内存淘汰机制

文章目录 &#x1f34a; Redis过期策略&#x1f389; 惰性删除流程&#x1f389; 定期删除流程 &#x1f389; 内存淘汰机制&#x1f389; RDB对过期key的处理&#x1f389; AOF对过期key的处理 &#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、C…

领导:给你一个项目,如何开展性能测试工作。我:***

01 怎么开展性能测试 01 测试的一般步骤 性能测试的工作是基于系统功能已经完备或者已经趋于完备之上的&#xff0c;在功能还不够完备的情况下没有多大的意义&#xff08;后期功能完善上会对系统的性能有影响&#xff0c;过早进入性能测试会出现测试结果不准确、浪费测试资源…

react项目实现文件预览,比如PDF、txt、word、Excel、ppt等常见文件(腾讯云cos)

使用腾讯云文档预览&#xff0c;需要开通文档预览功能&#xff0c;该功能需要收费的。 使用限制 如果需要图片预览、视频或音频可以使用获取下载链接。 页面代码 <button onClick() > {handleClick(myself/文档.xlsx)}>预览</button><div style{{ height:…

百度AI代码辅助工具Baidu Comate初体验

国内的程序员们也可以使用国产的代码辅助工具了。百度Comate智能代码助手正式上线SaaS版本&#xff0c;即日起可申请试用。官网&#xff08;https://comate.baidu.com/&#xff09;。 点开使用手册&#xff0c;先瞜一眼&#xff0c;后面再细看&#xff0c;手册里面有详细的说明…

yum管理openssh服务

文章目录 yum工具使用1.yum的配置文件2.yum仓库的管理本地仓库网络仓库 3.使用yum管理软件listcleanrepolistinstallupdatedowngraderemoveinfoprovideshistorydeplistgrouplistgroupinstall opensshsshd服务Secure Shell 示例ssh主机密钥配置免密登录SSH 安全注意事项 yum工具…

【文件操作】Java -操作File对象

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 文件操作 Java - File对象 Java - File对象 Fi…

Matlab绘制散点的95%置信区间图

Matlab常绘制95%置信区间图&#xff0c;主要使用到patch函数。 如果直接使用散点进行拟合&#xff0c;在patch函数绘制95%置信区间时&#xff0c;会绘制的很乱&#xff0c;这个是由于patch函数所导致的&#xff0c;其实这个问题在 Matlab绘制95%置信区间图 中已经讲到过&#…

JS 严格模式和正常模式详解

JavaScript 严格模式&#xff08;Strict Mode&#xff09;和正常模式&#xff08;Non-Strict Mode&#xff09;是用于控制 JavaScript 代码执行的两种不同模式。严格模式引入了一些限制和变化&#xff0c;旨在帮助开发人员编写更可靠、安全和高效的代码。在本文中&#xff0c;我…

js实现将文本生成二维码(腾讯云cos)

示例 页面代码 import { getQCodeUrl } from /utils/cosInstance; import { PageContainer } from ant-design/pro-components; import { Access, useAccess } from umijs/max; import { Button, Image } from antd; import { useState } from react;const AccessPage: Reac…

SpringCloud复习:(2)@LoadBalanced注解的工作原理

LoadBalanced注解标记了一个RestTemplate或WebClient bean使用LoadBalancerClient来进行负载均衡。 LoadBalancerAutoConfiguration类给带注解的RestTemplate添加了拦截器&#xff1a;LoadBalancerInterceptor. 具体流程如下&#xff1a; 首先定义一个LoadBalancerInterceptor…

超强满血不收费的AI绘图教程来了(在线Stable Diffusion一键即用)

超强满血不收费的AI绘图教程来了&#xff08;在线Stable Diffusion一键即用&#xff09; 一、简介1.1 AI绘图1.2 Stable Diffusion1.2.1 原理简述1.2.2 应用流程 二、AI绘图工具2.1 吐司TusiArt2.2 哩布哩布LibLibAI2.3 原生部署 三、一键即用3.1 开箱尝鲜3.2 模型关联3.3 Cont…

小白必看,手把手教你重装系统

一&#xff0c;安装步骤 二&#xff0c;重装之前需要做的准备 1、重装之前请大家务必注意备份重要资料。电脑有价&#xff0c;数据无价——重要数据备份之后&#xff0c;电脑随便折腾都没问题。大不了就是重装不成功。系统软件问题多试几次总能解决的&#xff0c;但重要数据一…