前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >现代C++编程实践(四)—手动撸一个泛型分割函数

现代C++编程实践(四)—手动撸一个泛型分割函数

作者头像
CPP开发前沿
发布2023-08-28 18:27:57
1390
发布2023-08-28 18:27:57
举报
文章被收录于专栏:CPP开发前沿CPP开发前沿

从接触C和C++,就开始对这两个语言着迷,后来接触了Java后,愈发对这两个语言着迷。不为别的,仅仅因为热爱。那种可以掌控一切的感觉,是任何一个Java程序员都体会不了的,不受制于人,自己掌握规则。

1 实现一个泛型分割函数

熟悉Java、C#以及Python的人都知道,在字符串处理时有一个split函数,非常有用,尤其在使用文件接口时,对方按照协议将内容以一定格式保存到文件中,我们要做的就是读取文件并解析文件。但是作为C/C++的我们,标准库里并没有现成的split接口可用,今天我们就使用现代C++手动实现一个C++版的分割函数。

代码实现并不复杂,先来看下代码实现:

代码语言:javascript
复制
 //重新构建一个string字符串
auto binFunc([](auto itA,auto itB){
    return std::string(itA,itB);
});
 //字符串分割函数
template<typename T1,typename T2,typename T3,typename T4>
T1 split(T1 begIt,T1 endIt,T2 outIt,T3 diaChar,T4 Func){
    while(begIt != endIt){
        auto sliceEnd(std::find(begIt,endIt,diaChar));
        *outIt++ = binFunc(begIt,sliceEnd);
        if(sliceEnd==endIt){
            return endIt;
        }
        begIt = std::next(sliceEnd);
    }
    return begIt;
}

如上,上面的接口实现了对字符串按照指定分隔符进行字符串分割。下面先来验证下代码的准确性,测试代码如下:

代码语言:javascript
复制
int main()
{
   std::list<std::string> listA;
   const std::string strValue{"org|userId|phoneNumber|country|addr|charge|duration|time"};
   split(std::begin(strValue),std::end(strValue),back_inserter(listA),'|',binFunc);
   std::copy(std::begin(listA),std::end(listA),ostream_iterator<std::string>{cout,","});
    return 0;
}

测试代码构造了一个字符串,字符串使用“|”进行分割,然后调用我们上面编写好的字符串分割接口,运行结果为:

代码语言:javascript
复制
org,userId,phoneNumber,country,addr,charge,duration,time,

从结果可知,字符串被正确分割。那么上面的分割函数具体是怎么工作的呢?

2 分割函数实现分析

在上面的实现中,split函数使用std::find查找分隔符的位置并使用sliceEnd保存当前迭代器的位置,然后使用while循环保证所有遍历完所有的字符串。

binFunc函数实现了将被分割的字符串重新构建成一个string并返回。这样在split函数中,就可以被保存在outIt中。outIt在实际调用时我们传入实际上一个迭代器,通过调用std::back_inserter接口。每次都会将binFunc返回的字符串插入容器中。这样,我们就实现了将字符串进行分割并保存。下面来具体说下实现过程中使用的一些算法:

  • std::back_inserter

std::back_inserter在实际编程时使用不多,这里大家可以做下了解,它的定义如下:

代码语言:javascript
复制
template <class Container>
  back_insert_iterator<Container> back_inserter (Container& x);

从上面的定义可知,它的参数是一个容器,主要实现的功能就是构造一个后向的迭代器并将元素插入到容器中,在上面的代码实现中就是使用了这个功能来保障分割的字符串被插入到链表中。

  • std::find

std::find平时使用较多,在此不做过多介绍,其定义形式如下:

代码语言:javascript
复制
template <class InputIterator, class T>
   InputIterator find (InputIterator first, InputIterator last, const T& val);

即遍历[first,last]区间内的元素并返回第一个和val值相等的迭代器。

  • std::next()

std::next主要是返回指定元素个数的迭代器,其定义如下:

代码语言:javascript
复制
template <class ForwardIterator>
  ForwardIterator next (ForwardIterator it,
       typename iterator_traits<ForwardIterator>::difference_type n = 1);

如上,在定义中有一个默认值参数,如果不传则默认1,在上面的字符串分割函数中就是只用默认参数。下面给出一个不使用默认参数的代码的例子。这个例子实现了容器元素的遍历并打印。

代码语言:javascript
复制
int main () {
  std::list<int> mylist,outlist;
  for (int i=0; i<10; i++) mylist.push_back (i*10);
  std::cout << "mylist:";
  std::for_each (mylist.begin(),
                 std::next(mylist.begin(),10),
                 [](int x) {
                     std::cout << ' ' << x;} );
  std::cout << '\n';
  return 0;
}

如上,代码运行后将会输出结果为:

代码语言:javascript
复制
mylist: 0 10 20 30 40 50 60 70 80 90

3 总结

其实,有很多种C++方法可以实现字符串分割功能,大家不妨参考下C++开源库boost,不得不说这个库非常强大,尤其是C++17版本中的文件处理库也来源于此。有兴趣不妨研究下。boost程序库推荐下面这本书,希望大家喜欢。

本文参考:

  • https://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5
  • https://cplusplus.com/
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-06-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CPP开发前沿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档