C++11:变长参数模板模拟java.lang.String.format格式化输出

本文介绍了一种使用C++11变长参数模板来模拟Java中String.format方法的技术。该实现支持基本算术类型及std::string,并通过递归调用snprintf处理格式化字符串。

java.lang.String中有一个很方便的方法format,可以将不同的类型的参数格式化输出成字符串,在C++下面并没有这么方便的函数来支持这个需求。
于是我用C++11的变长参数模板实现了String.format的简单模拟,完整代码如下:
string_utils.h

#pragma once
#include <string>
#include <cstdio>
#include <vector>
#include <regex>
#include <stdexcept>
namespace std {
	/*
	 * 简单模拟java.ang.String.format输出
	 * 除算术类型(int,long,float等)之外只支持std::string输出
	 * */
	class string_utils
	{
		// 普通类型直接返回值
		template<typename T>
		static T cvalue(T&& v){
			return std::forward<T>(v);
		}
		// std::string类型返回c-string指针
		static const char* cvalue( std::string& v){
			return v.c_str();
		}

		// 递归结束
		static int snprintf (char *__stream, size_t __n, const std::string &__format){
			if(__n<=0)return 0;
			// 正则表达式用于获取第一个格式化参数的%控制
			static std::regex fmt_first("^[\\s\\S]*?%[-+ #0]?(\\d+|\\*)?(\\.(?:\\d+|\\*))?(?:hh|h|l|ll|j|z|t|L)?[diuoxXfFeEgGaAcspn]");
			if(std::regex_match(__format,fmt_first)){
				// 实际参数数目与格式化字符串不匹配抛出异常
				throw std::logic_error("invalid format string:missing argument");
			}
			// 调用标准snprintf输出
			return std::snprintf(__stream,__n,__format.c_str());
		}
		template<typename ARG1,typename ...Args>
		static int snprintf (char *__stream, size_t __n, const std::string &__format, ARG1&& first,Args&&...args){
			if(__n<=0)return 0;
			// 正则表达式用于获取第一个格式化参数的%控制
			static std::regex fmt_first("^(?:[^%]|%%)*%[-+ #0]?(\\d+|\\*)?(\\.(?:\\d+|\\*))?(?:hh|h|l|ll|j|z|t|L)?[diuoxXfFeEgGaAcspn]");
			std::smatch m;
			if (!std::regex_search  ( __format, m, fmt_first )){
				// 没有找到%格式控制字符串则抛出异常
				std::cerr<<"extra argument provied to printf\n__format:"<<__format<<std::endl;
				throw std::logic_error("extra argument provied to printf");
			}
			// 调用标准snprintf函数输出第一个参数
			int num=std::snprintf(__stream,__n,m[0].str().c_str(),cvalue(std::forward<ARG1>(first)));
			// 递归调用处理剩余的参数,调整缓冲指针和长度
			return num+snprintf(__stream+num,size_t(__n-num),m.suffix().str(),std::forward<Args>(args)...);
		}
	public:
		// 类printf格式化输出字符串
		template<typename ...Args>
		static std::string format(const std::string &__format,Args&&...args){
			std::vector<char> buffer (size_t(1024));
			int num = snprintf ( buffer.data(), size_t(1024), __format, std::forward<Args>(args)...);
			return std::string(buffer.data(),buffer.data()+num);
		}
	};
}

测试代码:

int main() {
	std::string md5str="b9114c860f2b4bc7698c81a467487174";
	std::string fmt_str=std::string_utils::format(" md5str=%s ######size %d",md5str,md5str.size());
	std::cout<<fmt_str<<std::endl;
}
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

10km

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

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

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

打赏作者

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

抵扣说明:

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

余额充值