时间复杂度敏感的C++字符串分解split函数

至少到C++ 23,标准库中都没有提供string的split函数,于是就给了各显神通自造轮子的空间。boost中的实现,是分解成vector<string>&,这样处理,split函数中至少发生了一次全串级别的复制。作者在使用C++ 11写一个从巨量日志文件中提取特定字段的程序时,自造了一个返回所有分隔符位置的“轮子”,在函数体中不发生字符串复制:

template <class T>
std::vector<size_t> NSplit(const std::string& src, T delimiters)
{
	size_t nfrom, nfind;
	std::vector<size_t> result;
	nfrom=0;
	do {
		result.push_back(nfrom = nfind = src.find_first_of(delimiters, nfrom));
		nfrom++;
	} while(nfind != std::string::npos);
	return result;
}

template <class T>
std::vector<size_t>& NSplit(std::vector<size_t>& result, const std::string& src, T delimiters)
{
	size_t nfrom, nfind;
	result.clear();
	nfrom=0;
	do {
		result.push_back(nfrom = nfind = src.find_first_of(delimiters, nfrom));
		nfrom++;
	} while(nfind != std::string::npos);
	return result;
}
//调用方式示例1:
string src = "Str0\tStr1@Str2\tStr3";
size_t idx=0;
for( auto n : NSplit(src,"@\t") ) {
    cout << src.substr(idx, n-idx) << endl;
    idx = ++n;
}

//调用方式示例2:
#define NSplit_s(s,v,i) ((i)==0? s.substr(0,v[0]) : s.substr(v[(i)-1]+1,v[i]-v[(i)-1]-1))

string src = "Str0\tStr1@Str2\tStr3";
vector<size_t> v = NSplit(src, "@\t");
for( size_t i=0; i<v.size(); i++ )
    cout <<  NSplit_s(src,v,i) << endl;

可以看出,如果要在主程序中使用所有的子串,由于调用了substr,那么也会发生一次全串级别的复制,效率并不比boost的实现高。但是如果仅仅使用有限的几个子串,则效率通常要高许多。

C++ 17引入了string_view,效率问题就迎刃而解了:

template <class T>
std::vector<std::string_view> VSplit(const std::string& src, T delimiters)
{
	size_t nfrom, nfind;
	std::vector<std::string_view> result_views;
	if( !src.empty() ) {
        for( nfrom=0; (nfind = src.find_first_of(delimiters, nfrom)) != std::string::npos; nfrom=nfind+1 )
            result_views.emplace_back(src.data()+nfrom, nfind-nfrom);
        result_views.emplace_back(src.data()+nfrom, src.size()-nfrom);
    }
    return result_views;
}

template <class T>
std::vector<std::string_view>& VSplit(std::vector<std::string_view>& result_views, const std::string& src, T delimiters)
{
	size_t nfrom, nfind;
	result_views.clear();
	if( !src.empty() ) {
        for( nfrom=0; (nfind = src.find_first_of(delimiters, nfrom)) != std::string::npos; nfrom=nfind+1 )
            result_views.emplace_back(src.data()+nfrom, nfind-nfrom);
        result_views.emplace_back(src.data()+nfrom, src.size()-nfrom);
    }
    return result_views;
}
//调用方式示例:
string src = "Str0\tStr1@Str2\tStr3";
for( auto s : VSplit(src, "@\t") )
    cout << s << endl;

上述C++ 11和C++ 17的实现中,两个重载函数的效率差别属于C语言的基本常识,在此不做讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Python的split函数可以用于分隔字符串。如果要分隔时间,可以使用字符串格式化或正则表达式。字符串格式化可以将时间字符串按照指定的格式转换成一个datetime变量,然后再将这个变量的年、月、日、时、分、秒等拆分出来。例如,可以使用以下代码: ``` import datetime time_str = '2022-11-12 13:24:56' time_format = '%Y-%m-%d %H:%M:%S' time_obj = datetime.datetime.strptime(time_str, time_format) year = time_obj.year month = time_obj.month day = time_obj.day hour = time_obj.hour minute = time_obj.minute second = time_obj.second ``` 上述代码首先使用strptime函数字符串time_str按照格式time_format转换成datetime对象time_obj,然后将其年、月、日、时、分、秒等元素拆分出来。 如果使用正则表达式,可以通过指定正则表达式模式来匹配字符串中的时间元素,然后进行拆分。例如,可以使用以下代码: ``` import re time_str = '2022-11-12 13:24:56' pattern = r'(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})' match_obj = re.match(pattern, time_str) year = int(match_obj.group(1)) month = int(match_obj.group(2)) day = int(match_obj.group(3)) hour = int(match_obj.group(4)) minute = int(match_obj.group(5)) second = int(match_obj.group(6)) ``` 上述代码首先使用正则表达式模式pattern匹配字符串time_str中的年、月、日、时、分、秒等元素,然后使用group方法将其拆分出来。这里使用了re模块的match方法来进行匹配。需要注意的是,使用正则表达式进行分隔要比字符串格式化更加灵活,但也会带来一些额外的代码复杂度。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

martin_teddybear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值