StrUtil.hpp

source: wtcpp/folder98/folder02/folder1/file05.md

/*!
 * \file StrUtil.hpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief 字符串处理的封装
 */
#pragma once
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
#include <functional>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <cctype>

typedef std::vector<std::string> StringVector;

class StrUtil
{
public:

	

	/** Removes any whitespace characters, be it standard space or
	TABs and so on.
	@remarks
	The user may specify wether they want to trim only the
	beginning or the end of the std::string ( the default action is
	to trim both).
	*/
	static inline void trim(std::string& str, const char* delims = " \t\r", bool left = true, bool right = true)
	{
		if(right)
			str.erase(str.find_last_not_of(delims)+1);
		if(left)
			str.erase(0, str.find_first_not_of(delims));
	}

	static inline std::string trim(const char* str, const char* delims = " \t\r", bool left = true, bool right = true)
	{
		std::string ret = str;
		if(right)
			ret.erase(ret.find_last_not_of(delims)+1);
		if(left)
			ret.erase(0, ret.find_first_not_of(delims));

		return std::move(ret);
	}

	//去掉所有空格
	static inline void trimAllSpace(std::string &str)
	{
		std::string::iterator destEnd = std::remove_if(str.begin(), str.end(), [](const char& c){
			return c == ' ';
		});
		str.resize(destEnd-str.begin());
	}

	//去除所有特定字符
	static inline void trimAll(std::string &str,char ch)
	{
		std::string::iterator destEnd=std::remove_if(str.begin(),str.end(),std::bind1st(std::equal_to<char>(),ch));
		str.resize(destEnd-str.begin());
	}

	/** Returns a std::stringVector that contains all the substd::strings delimited
	by the characters in the passed <code>delims</code> argument.
	@param
	delims A list of delimiter characters to split by
	@param
	maxSplits The maximum number of splits to perform (0 for unlimited splits). If this
	parameters is > 0, the splitting process will stop after this many splits, left to right.
	*/
	static inline StringVector split( const std::string& str, const std::string& delims = "\t\n ", unsigned int maxSplits = 0)
	{
		StringVector ret;
		unsigned int numSplits = 0;

		// Use STL methods
		size_t start, pos;
		start = 0;
		do
		{
			pos = str.find_first_of(delims, start);
			if (pos == start)
			{
				ret.emplace_back("");
				// Do nothing
				start = pos + 1;
			}
			else if (pos == std::string::npos || (maxSplits && numSplits == maxSplits))
			{
				// Copy the rest of the std::string
				ret.emplace_back( str.substr(start) );
				break;
			}
			else
			{
				// Copy up to delimiter
				ret.emplace_back( str.substr(start, pos - start) );
				start = pos + 1;
			}
			// parse up to next real data
			//start = str.find_first_not_of(delims, start);
			++numSplits;

		} while (pos != std::string::npos);
		return std::move(ret);
	}

	/** Returns a std::stringVector that contains all the substd::strings delimited
	by the characters in the passed <code>delims</code> argument.
	@param
	delims A list of delimiter characters to split by
	@param
	maxSplits The maximum number of splits to perform (0 for unlimited splits). If this
	parameters is > 0, the splitting process will stop after this many splits, left to right.
	*/
	static inline void split(const std::string& str, StringVector& ret, const std::string& delims = "\t\n ", unsigned int maxSplits = 0)
	{
		unsigned int numSplits = 0;

		// Use STL methods
		size_t start, pos;
		start = 0;
		do
		{
			pos = str.find_first_of(delims, start);
			if (pos == start)
			{
				ret.emplace_back("");
				// Do nothing
				start = pos + 1;
			}
			else if (pos == std::string::npos || (maxSplits && numSplits == maxSplits))
			{
				// Copy the rest of the std::string
				ret.emplace_back(str.substr(start));
				break;
			}
			else
			{
				// Copy up to delimiter
				ret.emplace_back(str.substr(start, pos - start));
				start = pos + 1;
			}
			// parse up to next real data
			//start = str.find_first_not_of(delims, start);
			++numSplits;

		} while (pos != std::string::npos);
	}

	/** Upper-cases all the characters in the std::string.
	*/
	static inline void toLowerCase( std::string& str )
	{
		std::transform(
			str.begin(),
			str.end(),
			str.begin(),
			(int(*)(int))tolower);

	}

	/** Lower-cases all the characters in the std::string.
	*/
	static inline void toUpperCase( std::string& str )
	{
		std::transform(
			str.begin(),
			str.end(),
			str.begin(),
			(int(*)(int))toupper);
	}

	static inline std::string makeLowerCase(const char* str)
	{
		std::string strRet = str;
		std::transform(
			strRet.begin(),
			strRet.end(),
			strRet.begin(),
			(int(*)(int))tolower);
		return std::move(strRet);
	}

	static inline std::string makeUpperCase(const char* str)
	{
		std::string strRet = str;
		std::transform(
			strRet.begin(),
			strRet.end(),
			strRet.begin(),
			(int(*)(int))toupper);
		return std::move(strRet);
	}

	/** Converts the contents of the std::string to a float.
	@remarks
	Assumes the only contents of the std::string are a valid parsable float. Defaults to  a
	value of 0.0 if conversion is not possible.
	*/
	static inline float toFloat( const std::string& str )
	{
		return (float)atof(str.c_str());
	}

	static inline double toDouble( const std::string& str )
	{
		return atof(str.c_str());
	}

	/** Returns whether the std::string begins with the pattern passed in.
	@param pattern The pattern to compare with.
	@param lowerCase If true, the end of the std::string will be lower cased before
	comparison, pattern should also be in lower case.
	*/
	static inline bool startsWith(const std::string& str, const std::string& pattern, bool lowerCase = true)
	{
		size_t thisLen = str.length();
		size_t patternLen = pattern.length();
		if (thisLen < patternLen || patternLen == 0)
			return false;

		std::string startOfThis = str.substr(0, patternLen);
		if (lowerCase)
			toLowerCase(startOfThis);

		return (startOfThis == pattern);
	}

	/** Returns whether the std::string ends with the pattern passed in.
	@param pattern The pattern to compare with.
	@param lowerCase If true, the end of the std::string will be lower cased before
	comparison, pattern should also be in lower case.
	*/
	static inline bool endsWith(const std::string& str, const std::string& pattern, bool lowerCase = true)
	{
		size_t thisLen = str.length();
		size_t patternLen = pattern.length();
		if (thisLen < patternLen || patternLen == 0)
			return false;

		std::string endOfThis = str.substr(thisLen - patternLen, patternLen);
		if (lowerCase)
			toLowerCase(endOfThis);

		return (endOfThis == pattern);
	}

	/** Method for standardising paths - use forward slashes only, end with slash.
	*/
	static inline std::string standardisePath( const std::string &init, bool bIsDir = true)
	{
		std::string path = init;

		std::replace( path.begin(), path.end(), '\\', '/' );
		if (path[path.length() - 1] != '/' && bIsDir)
			path += '/';

		return std::move(path);
	}

	/** Method for splitting a fully qualified filename into the base name
	and path.
	@remarks
	Path is standardised as in standardisePath
	*/
	static inline void splitFilename(const std::string& qualifiedName,std::string& outBasename, std::string& outPath)
	{
		std::string path = qualifiedName;
		// Replace \ with / first
		std::replace( path.begin(), path.end(), '\\', '/' );
		// split based on final /
		size_t i = path.find_last_of('/');

		if (i == std::string::npos)
		{
			outPath = "";
			outBasename = qualifiedName;
		}
		else
		{
			outBasename = path.substr(i+1, path.size() - i - 1);
			outPath = path.substr(0, i+1);
		}
	}

	/** Simple pattern-matching routine allowing a wildcard pattern.
	@param str std::string to test
	@param pattern Pattern to match against; can include simple '*' wildcards
	@param caseSensitive Whether the match is case sensitive or not
	*/
	static inline bool match(const std::string& str, const std::string& pattern, bool caseSensitive = true)
	{
		std::string tmpStr = str;
		std::string tmpPattern = pattern;
		if (!caseSensitive)
		{
			toLowerCase(tmpStr);
			toLowerCase(tmpPattern);
		}

		std::string::const_iterator strIt = tmpStr.begin();
		std::string::const_iterator patIt = tmpPattern.begin();
		std::string::const_iterator lastWildCardIt = tmpPattern.end();
		while (strIt != tmpStr.end() && patIt != tmpPattern.end())
		{
			if (*patIt == '*')
			{
				lastWildCardIt = patIt;
				// Skip over looking for next character
				++patIt;
				if (patIt == tmpPattern.end())
				{
					// Skip right to the end since * matches the entire rest of the string
					strIt = tmpStr.end();
				}
				else
				{
					// scan until we find next pattern character
					while(strIt != tmpStr.end() && *strIt != *patIt)
						++strIt;
				}
			}
			else
			{
				if (*patIt != *strIt)
				{
					if (lastWildCardIt != tmpPattern.end())
					{
						// The last wildcard can match this incorrect sequence
						// rewind pattern to wildcard and keep searching
						patIt = lastWildCardIt;
						lastWildCardIt = tmpPattern.end();
					}
					else
					{
						// no wildwards left
						return false;
					}
				}
				else
				{
					++patIt;
					++strIt;
				}
			}

		}
		// If we reached the end of both the pattern and the string, we succeeded
		if (patIt == tmpPattern.end() && strIt == tmpStr.end())
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/// Constant blank std::string, useful for returning by ref where local does not exist
	static inline const std::string BLANK()
	{
		static const std::string temp = std::string("");
		return std::move(temp);
	}

	//地球人都知道,恶心的std::string是没有CString的Format这个函数的,所以我们自己造
	static inline std::string printf(const char *pszFormat, ...)
	{
		va_list argptr;
		va_start(argptr, pszFormat);
		std::string result=printf(pszFormat,argptr);
		va_end(argptr);
		return std::move(result);
	}

	//地球人都知道,恶心的std::string是没有CString的Format这个函数的,所以我们自己造
	static inline std::string printf2(const char *pszFormat, ...)
	{
		va_list argptr;
		va_start(argptr, pszFormat);
		std::string result=printf2(pszFormat,argptr);
		va_end(argptr);
		return std::move(result);
	}

	//地球人都知道,恶心的std::string是没有CString的Format这个函数的,所以我们自己造
	static inline std::string printf2(const char *pszFormat,va_list argptr)
	{
		int         size   = 1024;
		char*       buffer = new char[size];

		while (1)
		{
#ifdef _MSC_VER
			int n = _vsnprintf(buffer, size, pszFormat, argptr);
#else
			int n = vsnprintf(buffer, size, pszFormat, argptr);
#endif

			// If that worked, return a string.
			if (n > -1 && n < size)
			{
				std::string s(buffer);
				delete [] buffer;
				return s;
			}

			if (n > -1)     size  = n+1; // ISO/IEC 9899:1999
			else            size *= 2;   // twice the old size

			delete [] buffer;
			buffer = new char[size];
		}
	}

	static inline std::string extend(const char* str, uint32_t length)
	{
		if(strlen(str) >= length)
			return str;

		std::string ret = str;
		uint32_t spaces = length - (uint32_t)strlen(str);
		uint32_t former = spaces/2;
		uint32_t after = spaces - former;
		for(uint32_t i = 0; i < former; i++)
		{
			ret.insert(0, " ");
		}

		for(uint32_t i = 0; i < after; i++)
		{
			ret += " ";
		}
		return std::move(ret);
	}

	//地球人都知道,恶心的std::string是没有CString的Format这个函数的,所以我们自己造
	static inline std::string printf(const char* pszFormat, va_list argptr)
	{
		int size = 1024;
		int len=0;
		std::string ret;
		for ( ;; )
		{
			ret.resize(size + 1,0);
			char *buf=(char *)ret.c_str();   
			if ( !buf )
			{
				return BLANK();
			}

			va_list argptrcopy;
			va_copy(argptrcopy, argptr);

#ifdef _MSC_VER
			len = _vsnprintf(buf, size, pszFormat, argptrcopy);
#else
			len = vsnprintf(buf, size, pszFormat, argptrcopy);
#endif
			va_end(argptrcopy);

			if ( len >= 0 && len <= size )
			{
				// ok, there was enough space
				break;
			}
			size *= 2;
		}
		ret.resize(len);
		return std::move(ret);
	}

	//取得右边的N个字符
	static inline std::string right(const std::string &src,size_t nCount)
	{
		if(nCount>src.length())
			return BLANK();
		return std::move(src.substr(src.length()-nCount,nCount));
	}

	//取左边的N个字符
	static inline std::string left(const std::string &src,size_t nCount)
	{
		return std::move(src.substr(0,nCount));
	}

	static inline size_t charCount(const std::string &src,char ch)
	{
		size_t result=0;
		for(size_t i=0;i<src.length();i++)
		{
			if(src[i]==ch)result++;
		}
		return result;
	}

	static inline void replace(std::string& str, const char* src, const char* des)
	{
		std::string ret = "";
		std::size_t srcLen = strlen(src);
		std::size_t lastPos = 0;
		std::size_t pos = str.find(src);
		while(pos != std::string::npos)
		{
			ret += str.substr(lastPos, pos-lastPos);
			ret += des;

			lastPos = pos + srcLen;
			pos = str.find(src, lastPos);
		}
		ret += str.substr(lastPos, pos);

		str = ret;
	}

	static inline std::string fmtInt64(int64_t v)
	{
		char buf[64] = { 0 };
#ifdef _MSC_VER
		int pos = sprintf(buf, "%I64d", v);
#else
		int pos = sprintf(buf, "%lld", (long long)v);
#endif
		return buf;
	}

	static inline std::string fmtUInt64(uint64_t v)
	{
		char buf[64] = { 0 };
#ifdef _MSC_VER
		int pos = sprintf(buf, "%I64u", v);
#else
		int pos = sprintf(buf, "%llu", (unsigned long long)v);
#endif
		return buf;
	}
};