基于C++实现去除字符串头尾指定字符功能

 更新时间:2022年04月26日 15:09:03   作者:一只会铲史的猫  
编程时我们经常需要对字符串进行操作,其中有一项操作就是去除字符串的头(尾)指定的字符,比如空格。本文为大家详细介绍了如何利用C++实现这一效果,需要的可以参考一下

编程时我们经常需要对字符串进行操作,其中有一项操作就是去除字符串的头(尾)指定的字符,比如空格。通常我们会使用封装好的库函数或者类函数的Trim方法来实现,如果自己动手写一个TrimHead和TrimTail函数该如何实现呢? 

本文针对字符串头(尾)部指定的字符的去除,分别给出两个实现方法。并分别比较一下改进后的性能如何?

一、从头部开始去除指定字符

首先从头遍历,直到遇见第一个非指定字符,此后将后续字符按顺序逐一前移。

// 实现方式一
void TrimHead(char* pszSrc, char chTrim)
{
	if(NULL == pszSrc)
		return;
	
	// 从头部开始跳过chTrim指定的字符
	int i = 0;
	char* psz = pszSrc;
	while (*psz && *psz == chTrim) {
		i++;
		psz++;
	}
	
	// 从psz开始将后面字符逐一拷贝到前面
	i = 0;
	while(*psz)
	{
		*(pszSrc+i) = *psz;
		i++;
		psz++;
	}
	*(pszSrc+i) = 0;
}

上述函数中,在找到第一个非指定字符后,通过while函数逐一前移字符,如果后续字符串很长的话,性能是不是会比较低?我们改进一下,使用memmove函数替换while操作,下面是实现方法,代码更加简洁易读。

// 实现方式二
void TrimHeadEx(char* pszSrc, char chTrim)
{
	if(NULL == pszSrc)
		return;

	// 从头部开始跳过chTrim指定的字符
	int iStrLen = strlen(pszSrc);
	char* psz = pszSrc;
	while (*psz && *psz == chTrim) 
		psz++;

	// psz指向第一个非指定字符的位置
	if(psz != pszSrc)
	{
		// 计算新字符串长度
		iStrLen = iStrLen - (psz - pszSrc);
		memmove(pszSrc, psz, (iStrLen+1));	// +1表示将末尾的0也一并拷贝
	}
}

方法二的代码要比方法一的简洁,那么它的速度会比方法一的快么?文末会给出答案。

二、去除尾部指定的字符

// 实现方式一
void TrimTail(char* pszSrc, char chTrim)
{
	if(NULL == pszSrc)
		return;

	char* psz = pszSrc;
	char* pszLast = NULL;
	
	// 从头开始遍历直到整个字符串结束
	while(*psz)
	{
		// 遇到指定字符,则用pszLast记住该位置
		if(*psz == chTrim)
		{
			if(NULL == pszLast)
				pszLast = psz;
		}
		else
			pszLast = NULL;
		psz++;
	}
	
	// 如果找到末尾的第一个指定字符,则作为字符串的结尾
	if(pszLast != NULL)
		*pszLast = 0;
}

上述方法中,我们需要遍历完整个字符串,如果字符串很长的话,或者遇到极端情况,就是结尾没有指定字符时,也要将整个字符串遍历完毕。显然这种实现方式的效率并不高。 那么我们改进一下算法,从字符串的尾部进行遍历。

// 实现方式二
void TrimTailEx(char* pszSrc, char chTrim)
{
	if(NULL == pszSrc)
		return;

	// 从尾部开始跳过chTrim指定字符
	int iStrLen = strlen(pszSrc);
	char* pszStr = pszSrc;
	int iLastIdx = iStrLen - 1;
	while(iLastIdx >= 0 && *(pszStr+iLastIdx) == chTrim)
		iLastIdx--;
	
	// 计算新字符串长度并在结尾赋值为0
	iStrLen = iLastIdx+1;
	*(pszSrc+iStrLen) = 0;
}

上述实现方式是从字符串的尾部进行遍历,实现的方式也更加的简洁。如果结尾没有指定字符,该函数会在遍历第一个字符后就退出,性能显然要好过方式一。

那么对于TrimHead和TrimTail的两种实现,方式二和方式一到底谁快呢?是不是和我们想象的一样有差距或者差距很大呢? 

三、测试比较

这里写了一个测试函数TestSpeedTrim,为了让时间更加明显,在该函数中设置的循环次数为10000000。大家可以亲自运行测试一下,看看debug和release两个版本的差异,结果一定会让你吃惊,可能和你想的并不一样哦。

#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void TestSpeedTrim(bool bTrimHead)
{
	char szTrim1[256] = {0};
	char szTrim2[256] = {0};
	
	char* pszOrigin = "     This is a trim test head/tail    ";
	strcpy(szTrim1, pszOrigin);
	strcpy(szTrim2, pszOrigin);
	
	int i = 0;
	int iCount = 10000000;
	clock_t cStart = 0;
	
	// 第一种Trim方法
	cStart = clock();
	for(i = 0; i < iCount; i++)
	{
		bTrimHead ? TrimHead(szTrim1, ' ') : TrimTail(szTrim1, ' ');
	}
	clock_t cSpan1 = clock() - cStart;
	
	// 第二种Trim方法
	cStart = clock();
	for(i = 0; i < iCount; i++)
	{
		bTrimHead ? TrimHeadEx(szTrim2, ' ') :	TrimTailEx(szTrim2, ' ');
	}
	clock_t cSpan2 = clock() - cStart;
	
	printf("cSpan1 = %d, cSpan2 = %d\r\n", cSpan1, cSpan2);
	printf("szTrim1=[%s]\r\n", szTrim1);
	printf("szTrim2=[%s]\r\n", szTrim2);
}

int main(int argc, char* argv[])
{
	// 测试头
	printf("删除头部的空字符:\r\n");
	TestSpeedTrim(true);

	// 测试尾
	printf("\r\n删除尾部的空字符:\r\n");
	TestSpeedTrim(false);

	getchar();
	return 0;
}

这里就不给出比较结果了,因为只有自己亲自动手实现并跑一遍后,才会记得更加牢靠。

到此这篇关于基于C++实现去除字符串头尾指定字符功能的文章就介绍到这了,更多相关C++去除字符串指定字符内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++基于蔡基姆拉尔森计算公式实现由年月日确定周几的方法示例

    C++基于蔡基姆拉尔森计算公式实现由年月日确定周几的方法示例

    这篇文章主要介绍了C++基于蔡基姆拉尔森计算公式实现由年月日确定周几的方法,涉及C++针对日期时间的数值运算相关操作技巧,需要的朋友可以参考下
    2017-07-07
  • C语言通过二分查找实现猜数字游戏

    C语言通过二分查找实现猜数字游戏

    这篇文章主要为大家详细介绍了在C语言中如何通过二分查找思想编写一个简单的猜数字游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-02-02
  • C C++ 算法实例大全

    C C++ 算法实例大全

    这篇文章主要介绍了C C++ 算法实例大全,里面大量的实例介绍,学习c语言的朋友可以收藏
    2016-12-12
  • C++ 将字符串值赋给CHAR数组的实现

    C++ 将字符串值赋给CHAR数组的实现

    这篇文章主要介绍了C++ 将字符串值赋给CHAR数组的实现,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • C++ list-map链表与映射表的简单使用

    C++ list-map链表与映射表的简单使用

    本文主要介绍了C++ list-map链表与映射表的简单使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • 一篇文章带你了解C语言的选择结构

    一篇文章带你了解C语言的选择结构

    这篇文章主要为大家介绍了C语言的选择结构,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • C++ Boost Xpressive示例分析使用

    C++ Boost Xpressive示例分析使用

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-11-11
  • C语言指针和数组深入探究使用方法

    C语言指针和数组深入探究使用方法

    在C语言和C++等语言中,数组元素全为指针变量的数组称为指针数组,指针数组中的元素都必须具有相同的存储类型、指向相同数据类型的指针变量。指针数组比较适合用来指向若干个字符串,使字符串处理更加方便、灵活
    2022-08-08
  • C语言实现可增容动态通讯录详细过程

    C语言实现可增容动态通讯录详细过程

    这篇文章主要为大家介绍了C语言实现简易通讯录的完整流程,此通讯录还可以增容,并且每个环节都有完整代码,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2022-05-05
  • 详解C语言内核字符串拷贝与比较

    详解C语言内核字符串拷贝与比较

    本文将探索一下字符串的拷贝与比较,与应用层不同内核字符串拷贝与比较也需要使用内核专用的API函数,字符串的拷贝往往伴随有内核内存分配,我们将首先简单介绍内核如何分配堆空间,然后再以此为契机简介字符串的拷贝与比较
    2022-09-09

最新评论