STL(四) std::string /std::wstring 查找、删除、替换(find erase replace)

2023-11-05

std::string(std::wstring)类,在C++中是一个非常重要的存在,不管程序规模大小,很难避免不用到。

功能很强大,但是总感觉距离“好用”还差了那么一点点。

首先,需要明白一点,std::string是STL中的一员,所以,有关stl的诸多算法和理念,都适用于它。

有关std::string的基本操作,不过多介绍,到处都能找到,这篇博客,重点介绍平常编程经常遇到的字符串的查找、替换和删除操作。

查找

std::string 的查找,用std::find函数当然也没问题,但是,其本身有很多关于查找的成员函数,使用起来更便捷,具体如下:

所有函数的返回值都是size_t。

从函数名就很容易理解函数的功能,拿find_first_of来说,查找第一个符合条件的元素。例子与后面的删除操作一起列出。

删除

删除函数为erase,也是成员函数:

从原型看,三种类型,删除的都是指定区间或者某个具体的迭代器,而不是某个字符或者字符串,这与我们平时理解的删除有点不太一样。

编程中遇到的,大多都是具体的删除,例如删除字符串中的所有空格、删除首尾的空格等等,所以前面才会说,std::string提供的成员函数,距离好用,还差了一点点。很多时候,需要我们重新封装一下。

比如,想实现删除所有空格(指定字符),怎么做呢?上一篇介绍过,vector想要删除某个元素,需要搭配erase成员函数和std::remove一起实现,std::string也是如此。

设字符串变量名为str,一句代码就能实现:

str.erase(std::remove(str.begin(), str.end(), ' '), str.end());

这里不过多介绍,具体原理,可以参考上一篇:STL(三)删除元素 remove、erase

如果是删除首尾的空格呢?

除了以上的查询函数外,还需要用到获取子串的substr函数。

找到第一个非空字符的位置iStart, 最后一个非空字符的位置iEnd,获取iStart到iEnd的子串,或者删除0到iStart以及iEnd到字符串末尾的字符。但是需要注意,首尾可能都没有空格,及iStart和iEnd都可能为std::string::npos(字符串里面只有空格或者空字符串)。

这里以获取iStart到iEnd的子串为例,封装接口如下:

size_t Trim(std::string& strValue, char ch = ' ')
{
    size_t iCount = strValue.size();
    size_t iStart = strValue.find_first_not_of(ch);
    if (std::string::npos == iStart)
    {
        strValue.clear();
        return iCount;
    }
    size_t iEnd = strValue.find_last_not_of(ch);
    strValue = strValue.substr(iStart, iEnd - iStart + 1);
    return iCount - iEnd + iStart - 1;
}

这里,if (std::string::npos == iStart),判断是否没有非空字符,如果std::string::npos == iStart,则iEnd必定也是std::string::npos,没必要继续下去。

Trim加入了一个参数ch,除了删除空格外,还能删除其他字符,返回值是删除的字符个数。

要测试不同字符串的执行结果,将执行和打印封装成一个函数,如下:

void ErasePrint(std::string& strValue)
{
    using std::cout;
    using std::endl;

    const std::string strEndSign = "***";    
    cout << "原始字符串:" << strValue << strEndSign << endl;
    size_t iEraseCount = Trim(strValue, ' ');
    cout << "删除后:" << strValue << strEndSign << endl;
    cout << "删除个数:" << iEraseCount << endl;
}

 

这里,定义了一个结束的字符串const std::string strEndSign = "***";  因为控制台打印后,字符后面都是一片空白,看不出来是否有空格。

主函数如下:

int _tmain(int argc, _TCHAR* argv[])
{
	std::string strValue = "  I Love You ";
	ErasePrint(strValue);

	strValue = "   ";
	ErasePrint(strValue);

	strValue = "";
	ErasePrint(strValue);

	system("pause");
	return 0;
}

 

执行结果:

至于用erase,原理差不多,这里不过多赘述。

但是,这里是删除单个字符,如果想要删除字符串呢?

删除字符串,某种意义,是替换字符串的一个子集,即将想要删除的字符串替换成空的字符串。所以,删除字符串,直接看下面的替换即可。

替换

std::string类有一个现成的替换函数:replace。形式很多,如下:

不难看出,不管参数是什么,功能都类似:将指定字符串,替换原字符串中指定区间的元素。

这似乎与平常理解的替换又有一些不一样,正常情况下,我们的需求替换大部分是这样的:用一个新的子串(字符),替换原字符串中指定的子串(字符)。

利用上面的replace,以及find,可以实现,如下:

size_t Replace(std::string& strValue, const std::string& strOld, const std::string& strNew)
{
    size_t iCount = 0;
    if (strOld.empty())
        return iCount;
    std::string::size_type iFind = 0;
    while (true)
    {
        iFind = strValue.find(strOld, iFind);
        if (std::string::npos == iFind)
            break;
        strValue.replace(iFind, strOld.size(), strNew);
        ++iCount;
        iFind += strNew.size();
    }
    return iCount;
}

 

这里需要注意几个地方:

1、新替换进来的字符串,可能和原来字符串和重新组成满足条件的子串。比如原始字符串为“aaac”,将要将“aa”替换成"ba",第一次替换后,原始字符串就成了"baac",此时如果再重头再替换,中间的aa还会被替换一次,显然不是想要的结果;

2、被替换的字符串是空的该如何处理?

以上接口,已经考虑到这个问题,如果还有什么未考虑到的,欢迎留言批评指正。

同样的,封装一个执行打印函数,如下:

void ReplacePrint(std::string& strValue, const std::string& strOld, const std::string& strNew)
{
	using std::cout;
	using std::endl;

	cout << "原始字符串:" << strValue << endl;
	int iEraseCount = Replace(strValue, strOld, strNew);
	cout << "替换后:" << strValue << endl;
	cout << "替换次数:" << iEraseCount << endl;
}

主函数中测试,如下:

int _tmain(int argc, _TCHAR* argv[])
{
	std::string strValue = "  I Love You ";
	ReplacePrint(strValue, " ", "");

	strValue = "aaac";
	ReplacePrint(strValue, "aa", "ba");

	strValue = "12345";
	ReplacePrint(strValue, "", "11");

	system("pause");
	return 0;
}

执行结果如下:

基本满足要求。

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STL(四) std::string /std::wstring 查找、删除、替换(find erase replace) 的相关文章

随机推荐