C#|.net core 基础 - 删除字符串最后一个字符的七大类N种实现方式
今天想通过和大家分享如何删除字符串最后一个字符的N种实现方法,来回顾一些基础知识点。
01第一类、字符串方式
这类方法是通过string类型自身方法直接实现。
1、Substring方法
相信大多数人第一个想到的可能就是这个方法。Substring方法是字符串内置方法,可以通过指定起始索引位置为0以及长度为字符串长度减1,直接截取指定长度的子字符串,从而达到删除最后一个字符目的。
示例代码如下:
public static string StringSubstring(string source)
{return source.Substring(0, source.Length - 1);
}
2、范围运算符
这个方法可以说是最简洁的方法,可能大家用的不是很多。范围运算符是从C# 8开始支持的。它的形式如:variate[start…end],指定某一索引范围的开头和末尾作为其操作数。左侧操作数是范围的包含性开头。右侧操作数是范围的不包含性末尾。任一操作数都可以是序列开头或末尾的索引。
下面列举了表达集合范围的各种方法:
范围运算符也适用于字符串,实现代码如下:
public static string StringRangeOperator(string source)
{return source[..^1];
}
3、Remove方法
Remove方法是字符串内置方法,可以删除从指定起始索引位置起到结尾的所有字符,因此可以把起始索引定为最后一个字符,从而达到删除最后一个字符目的。
示例代码如下:
public static string StringRemove(string source)
{return source.Remove(source.Length - 1);
}
4、Create方法
Create方法是字符串的静态方法,这个方法相信大家用的比较少,其作用是创建一个具有特定长度的新字符串,并在创建后使用指定的回调对其进行初始化。下面我们直接看下实现代码:
public static string StringCreate(string source)
{return string.Create(source.Length - 1, source, (span, state) =>{for (var i = 0; i < state.Length - 1; i++){span[i] = state[i];}});
}
下面对上面代码做个简单解释,第一个参数source.Length - 1是创建比原字符串长度少1位的目标字符串;第二个参数source是把原字符串当作参数传入,用于给第三个参数使用;第三个参数是一个两个参数无返回值委托,其中span参数表示目标字符串对应的Span,state参数表示原字符串即第二个参数值,for循环即是把原字符串字符循环赋值给目标字符串。
5、小结
上面四种方法主要是使用了字符串自身的内置方法进行操作,下面我们对四个方法进行三组对比性能测试,每组分别为长度为100、1000、10000的字符串。
通过测试结果不难发现,除了Create方法,其他三个方法差别不大,综合来看可以说Remove最优。
02第二类、StringBuilder方式
如果需要对大量字符串操作,相信大家会立即想到用StringBuilder来进行性能优化,下面简单介绍两种使用StringBuilder方式来删除字符串最后一个字符。
1、Append方法
字符串就相当于字符数组,因此我们可以循环字符串,然后使用StringBuilder的Append方法进行拼接,实现代码如下:
public static string StringBuilderAppend(string source)
{var sb = new StringBuilder();for (var i = 0; i < source.Length - 1; i++){sb.Append(source[i]);}return sb.ToString();
}
2、Length方式
相信大家看到这个标题应该比较疑惑,这是什么意思,我们先看代码再讲解:
public static string StringBuilderLength(string source)
{var sb = new StringBuilder(source);sb.Length--;return sb.ToString();
}
首先第一行代码表示通过原字符串创建一个可变字符串;重点就在第二行,直接对StringBuilder长度执行减1操作;最后再把StringBuilder转为字符串返回。
首先StringBuilder的Length属性表示当前可变字符串包含的字符数,当对其进行减1操作时,相当于告诉StringBuilder对象忽略最后一个字符,其内部并没有真的删除任何字符,被忽略的字符仍包含再StringBuilder对象内部,只是不再将其视为字符串的一部分,因此在调用.ToString方法时返回的就是我们想要的字符串。
3、小结
下面我们对两个方法进行三组对比性能测试,每组分别为长度为100、1000、10000的字符串。
通过这组测试结果很容易发现,直接操作Length属性性能显著优越于Append方法,但是和字符串直接操作的方式相比还差了不少。
03第三类、Array方式
上面我们提到字符串相当于字符数组,因此我们可以直接使用数组相应的方法。
1、For方法
我们可以直接构建一个目标字符数组,然后把原字符串中相应的字符复制到新字符数组中,最后把新字符数组转成字符串返回即可,代码如下:
public static string ArrayFor(string source)
{var chars = new char[source.Length - 1];for (var i = 0; i < chars.Length; i++){chars[i] = source[i];}return new string(chars);
}
2、Resize 方法
这个方法大家可能用的比较少,它可以把数组元素个数更改为指定的大小。其思想有点像上面StringBuilder对象直接修改Length属性。下面直接看看代码:
public static string ArrayResize(string source)
{var chars = source.ToCharArray();Array.Resize(ref chars, chars.Length - 1);return new string(chars);
}
3、CopyTo方法
这个方法相信大家应该有点影响,我们前面的文章也有提到过。简单来说就是把原数组复制到目标数组中,代码如下:
public static string ArrayCopyTo(string source)
{var chars = new char[source.Length - 1];source.CopyTo(0, chars, 0, chars.Length);return new string(chars);
}
4、String方式
String方式是值当把原字符串转换为字符数组后,直接使用String构造方法从字符数组中指定位置处开始并指定长度,来获取我们想要的结果。代码如下:
public static string ArrayString(string source)
{var chars = source.ToCharArray();return new string(chars, 0, chars.Length - 1);
}
其中字符串构造函数第一个参数表示字符数组,第二个参数表示从字符数组第0个索引开始,第三个参数表示取字符数组的元素个数。
5、小结
同样对上面四种方法进行三组对比性能测试,每组分别为长度为100、1000、10000的字符串。
通过测试结果不难发现,CopyTo方法和String方式相对较好,比之StringBuilder方式还要好些。
04第四类、Linq方式
Linq方式的核心思想是通过Linq方法获取目标字符串对应的字符数组,然后再转为字符串返回。
1、Take方法
Take方法主要作用是从序列的开头返回指定数目的连续元素,因此代码实现如下:
public static string LinqTake(string source)
{return new string(source.Take(source.Length - 1).ToArray());
}
2、SkipLast方法
SkipLast方法是从C# 8才开始有的,其作用是返回集合排除最后指定个数的元素外的所有元素。
public static string LinqSkipLast(string source)
{return new string(source.SkipLast(1).ToArray());
}
3、Range + Select方法
Range方法相信大家用的也比较少,其作用是生成指定范围内的整数序列。我们先来看代码然后再做解释:
public static string LinqRange(string source)
{return new string(Enumerable.Range(0, source.Length - 1).Select(i => source[i]).ToArray());
}
这里Range方法相当于生成了目标字符串索引序列,即[0… source.Length - 1],然后再通过Seletc方法取原字符串相应的字符,最后得到结果。
4、小结
同样对上面三种方法进行三组对比性能测试,每组分别为长度为100、1000、10000的字符串。
通过测试结果不难发现,Range + Select方法相对较好,但是比之前几类方法就差的太远了。
05第五类、Linq + String组合方式
这类方法是通过Linq方法和字符串方法组合的方式实现。
1、Concat方法
Concat方法是字符串的静态方法可以连接多个字符成为一个新的字符串,然后通过Linq的SkipLast方法配合达到我们的目的,代码如下:
public static string LinqStringConcat(string source)
{return string.Concat(source.SkipLast(1));
}
2、Join方法
Join方法也是字符串的静态方法,主要作用是使用指定的分隔符连接集合的成员。因此也可以达到Concat类似的效果。
public static string LinqStringJoin(string source)
{return string.Join("", source.SkipLast(1));
}
3、小结
下面我们对两个方法进行三组对比性能测试,每组分别为长度为100、1000、10000的字符串。
通过这组测试结果说明两者相差不大,相对于之前的方法更差了。
06第六类、数据视图方式
数据视图方式的核心思想是通过Span、Memory和ArraySegment实现。
1、AsSpan方法
Span是一个轻量级的、非托管的视图,用于表示连续的内存块。它可以直接操作栈上的内存。AsSpan方法可以通过指定起始索引和长度,直接在原字符串上获取到目标字符串视图,然后转成字符串返回,代码实现如下:
public static string Span(string source)
{var span = source.AsSpan(0, source.Length - 1);return new string(span);
}
2、AsMemory方法
Memory也是一个内存视图,但与 Span 不同,它可以存储在 heap 上。AsMemory方法用法和AsSpan方法类似,代码如下:
public static string Memory(string source)
{var memory = source.AsMemory(0, source.Length - 1);return new string(memory.Span);
}
3、ArraySegment方法
ArraySegment封装了对数组的一部分的引用,并维护了该部分的起始位置和长度。
public static string ArraySegment(string source)
{var segment = new ArraySegment<char>(source.ToCharArray(), 0, source.Length - 1);return new string(segment.Array, segment.Offset, segment.Count);
}
4、小结
同样对上面三种方法进行三组对比性能测试,每组分别为长度为100、1000、10000的字符串。
通过测试结果可以发现,三种方法性能都是相当高,当然其中ArraySegment方法相对要差一些。总统来说数据视图方式已经和第一类字符串方式不相上下了。
07第七类、正则表达式方式
这里解释两种正则表达式实现的方法。
1、Replace方法
Replace方法是Regex的静态方法,代码如下:
public static string RegexReplace(string source)
{return Regex.Replace(source, ".$", "");
}
2、Match方法
Match方法也是Regex的静态方法,代码如下:
public static string RegexMatch(string source)
{var match = Regex.Match(source, @"^(.*).$");return match.Groups[1].Value;
}
3、小结
下面我们对两个方法进行三组对比性能测试,每组分别为长度为100、1000、10000的字符串。
通过这组测试结果说明两者相差不大,相对于之前的方法性能差别居中。
从整体来看,使用第一类字符串方式性能又高代码又简洁是最优选,而列举了那么多种方法主要目的还是熟悉一些基础方法,虽然在这个案例里不是最优解,但是说不定在其他地方就用的恰到好处。
我们都知道做同样一件事件可能有很多种方法,然后可以选择出一种最优的方法,但是这个前提是你要知道这些方法是什么,你才能有的选。
注:测试方法代码以及示例源码都已经上传至代码库,有兴趣的可以看看。https://gitee.com/hugogoos/Planner
相关文章:

C#|.net core 基础 - 删除字符串最后一个字符的七大类N种实现方式
今天想通过和大家分享如何删除字符串最后一个字符的N种实现方法,来回顾一些基础知识点。 01第一类、字符串方式 这类方法是通过string类型自身方法直接实现。 1、Substring方法 相信大多数人第一个想到的可能就是这个方法。Substring方法是字符串内置方法&#…...

成都睿明智科技有限公司怎么样靠谱吗?
随着短视频与直播的深度融合,抖音电商凭借其强大的流量入口、精准的算法推荐以及便捷的购物体验,迅速崛起。对于传统企业和新兴品牌而言,这无疑是一个不可多得的机遇。然而,如何在这片红海中脱颖而出,就需要借助专业的…...

docker简述
1.安装dockers,配置docker软件仓库 安装,可能需要开代理,这里我提前使用了下好的包安装 启动docker systemctl enable --now docker查看是否安装成功 2.简单命令 拉取镜像,也可以提前下载使用以下命令上传 docker load -i imag…...

第27周:Transformer实战:文本分类
目录 前言 一、前期准备 1.1 环境安装 1.2 加载数据 二、数据预处理 2.1 构建词典 2.2 生成数据批次和迭代器 2.3 构建数据集 三、模型构建 3.1 定义位置编码器 3.2 定义Transformer模型 3.3 初始化模型 3.4 定义训练函数 3.5 定义评估函数 四、训练模型 4.1 模…...

在QT中将Widget提升为自定义的Widget后,无法设置Widget的背景颜色问题解决方法
一、问题 在Qt中将QWidget组件提升为自定义的QWidget后,Widget设置的样式失效,例如设置背景颜色为白色失效。 二、解决方法 将已经提升的QWidget实例对象,脱离父窗体的样式,然后再重新设置自己的样式。...

【学习笔记】手写一个简单的 Spring IOC
目录 一、什么是 Spring IOC? 二、IOC 的作用 1. IOC 怎么知道要创建哪些对象呢? 2. 创建出来的对象放在哪儿? 3. 创建出来的对象如果有属性,如何给属性赋值? 三、实现步骤 1. 创建自定义注解 2. 创建 IOC 容器…...

日记学习小迪安全27
感觉复制粘贴没有意思,而且还有点浪费时间,主要是学习,不是复制,那就复制别人的吧 第27关就参考这篇文章吧,以下大部分内容都是参考以下文章(侵权删除) 第27天:WEB攻防-通用漏洞&a…...

【React】类组件和函数组件
构建组件的方式 函数式组件(function)createElement(不建议使用)类组件形式创建(不建议使用) 对于 React 的理解 React, 用于构建用户界面的JavaScript库,本身只提供了Ul层面的解决方案。&am…...

Spring Boot应用开发
Spring Boot是一个基于Spring框架的开源Java框架,旨在简化新Spring应用的初始化和开发过程。它通过提供各种默认配置,减少了繁琐的配置,使开发者能够专注于业务逻辑的实现。本文将介绍Spring Boot的基本概念、优点、关键特性以及如何构建一个…...

mysql事务使用和事务隔离级别与sqlserver的比较
在 MySQL 中,事务 (Transaction) 是一个将一组 SQL 语句作为一个整体执行的机制。事务确保要么所有操作都执行成功,要么在遇到错误时回滚到之前的状态,从而保证数据库数据的一致性和完整性。 事务的四大特性(ACID) 事…...

双光吊舱图像采集详解!
一、图像采集 可见光图像采集: 使用高性能的可见光相机,通过镜头捕捉自然光或人工光源照射下的目标图像。 相机内部通常配备有先进的图像传感器,如CMOS或CCD,用于将光信号转换为电信号。 红外图像采集: 利用红外热…...

1688商品详情关键词数据-API
要利用 Python 爬虫采集 1688 商品详情数据,需要先了解 1688 网站的页面结构和数据请求方式。一般使用 requests 库请求网站的数据,使用 BeautifulSoup 库解析网页中的数据。 以下是一个简单的 Python 爬虫采集 1688 商品详情数据的示例代码:…...

vue 的属性绑定
双大括号不能在 HTML attributes 中使用。想要响应式地绑定一个 attribute,应该使用 v-bind 指令。 <template> <div v-bind:class"boxClass" v-bind:id"boxId"> </div> </template><script> export default{da…...

【附源码】Python :打家劫舍
系列文章目录 Python 算法学习:打家劫舍问题 文章目录 系列文章目录一、算法需求二、解题思路三、具体方法源码方法1:动态规划(自底向上)方法2:动态规划(自顶向下)方法3:优化的动态…...

YOLO11改进 | 注意力机制| 对小目标友好的BiFormer【CVPR2023】
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 本文介绍了一种新颖的动态稀疏注意力机制…...

高级Python开发工程师的面试备考指南
目录 博客标题:高级Python开发工程师的面试备考指南:30个面试问题与详细解析岗位职责问题解析1. 公司产品功能开发和代码维护2. 技术方案与项目计划制定3. 算法基础与代码优化4. 项目管理与团队协作任职要求问题解析5. Python 开发经验6. 数据处理相关库(Pandas, Numpy, Mat…...

【Java】JAVA知识总结浅析
Java是一门功能强大的编程语言,广泛应用于多个领域。Java的编程思想,包括面向过程和面向对象编程,Java的发展历史,各版本的特点,JVM原理,数据类型,Java SE与Java EE的区别,应用场景&…...

23-云原生监控系统
├──23-云原生监控系统 | ├──1-Prometheus监控 | | ├──1-二进制方式部署Prometheus监控系统 | | ├──2-二进制方式部署Prometheus监控系统告警 | | ├──3-容器化构建Prometheus监控系统 | | ├──4-容器监控方案CAdvisor | | └──5-k8s监…...

信息安全工程师(40)防火墙技术应用
一、防火墙的基本概念 防火墙是一种网络安全设备,用于监控和控制网络流量,以保护网络免受未经授权的访问和攻击。它可以是装配多张网卡的通用计算机,也可能是通用的物理设备。防火墙通过在网络之间设置访问控制策略,对进出的通信流…...

Liquid AI与液态神经网络:超越Transformer的大模型架构探索
1. 引言 自2017年谷歌发表了开创性的论文《Attention Is All You Need》以来,基于Transformer架构的模型迅速成为深度学习领域的主流选择。然而,随着技术的发展,挑战Transformer主导地位的呼声也逐渐高涨。最近,由麻省理工学院(M…...

Spring Boot 进阶-详解Spring Boot中使用Swagger3.0
在上篇文章中我们介绍了Spring Boot 整合Swagger3.0的一些基础用法,这篇文章中我们来深入学习一下Swagger3.0 还有其他高级用法。 在日常的开发中,为了减少工作量,我们会遇到一种情况,就是将前端的接口与后端的接口编写到同一个代码中,这样也提高了代码的复用率,减少了重…...

Linux平台Kafka高可用集群部署全攻略
🐇明明跟你说过:个人主页 🏅个人专栏:《大数据前沿:技术与应用并进》🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、Kafka简介 2、Kafka核心优势 二、环境准备 1…...

Android中有哪些布局方式?
Android中的布局方式是实现用户界面设计的基础,通过合理的布局,可以创建出美观且易用的应用程序界面。Android提供了多种布局方式,每种布局方式都有其特定的应用场景和特点。以下是对Android中主要布局方式的详细介绍: 一、线性布…...

Apache Ranger 70道面试题及参考答案
什么是Apache Ranger? Apache Ranger Apache Ranger 是一个用于 Hadoop 生态系统的集中式安全管理框架,旨在为 Hadoop 及相关大数据技术提供全面的安全解决方案。 它具有以下主要特点和功能: 一、访问控制管理 细粒度的权限控制:可以对 Hadoop 生态系统中的各种组件(如 H…...

2024年9月30日--10月6日(ue5肉鸽结束,20小时,共2851小时)
按照月计划,本周把ue肉鸽游戏完成,然后进行ue5太阳系 , 剩余14节,218分钟,如果按照10分钟的视频教程1小时进行完的话,则需要22小时,分布在10月2日-10月6日之间,每天44分钟的视频教程…...

什么是静态加载-前端
什么是前端静态加载 在前端开发中,静态加载是一种常见且重要的技术。简单来说,前端静态加载指的是在页面加载时将所需的资源(如HTML、CSS、JavaScript、图片等)一并加载到用户的浏览器中。这种方式有助于提高页面的加载速度和用户…...

(01)python-opencv基础知识入门(图片的读取与视频打开)
前言 一、图像入门 1.1 读取图像cv.imread() 1.2 数组数据转换cv.cvtColor() 1.3数据窗口展示 1.4图像保存 1.5图像的截取 1.6 图像的比例缩放 二、视频入门 参考文献 前言 OpenCV 于 1999 年由 Gary Bradsky 在英特尔创立,第一个版本于 2000 年问世。Vad…...

quic-go实现屏幕广播程序
最近在折腾quic-go, 突然想起屏广适合用udp实现,而http3基于quic-go,后者又基于udp, 所以玩一下。 先贴出本机运行效果图: 功能(实现)说明: 1.服务器先启动作为共享屏幕方,等待客户端连接上来 2.客户端连接 3.客户…...

C#操作SqlServer数据库语句
操作数据库语句 操作数据库语句需要搭配数据库的连接Connection类 和下达SQL命令Command类 1. ExecuteNonQuery ExecuteNonQuery 方法主要用来更新数据。通常使用它来执行Update、Insert和Delete语句,最后执行sql语句的时候可以用一个整形变量来接收,返…...

Linux之实战命令33:mount应用实例(六十七)
简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【…...