news 2026/11/2 6:09:03

C++ std::string扩展

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ std::string扩展

strUtil.h

#pragma once #include <cctype> #include <vector> #include <memory> #include <sstream> #include <type_traits> #include <string_view> #include <algorithm> namespace cpv { /** Return whether string starts with given pattern */ static inline bool startsWith(std::string_view str, std::string_view pattern) { return (str.size() >= pattern.size() && str.substr(0, pattern.size()) == pattern); } /** Return whether string ends with given pattern */ static inline bool endsWith(std::string_view str, std::string_view pattern) { return (str.size() >= pattern.size() && str.substr(str.size() - pattern.size()) == pattern); } /** * Split string with specified characters. * Call func(parts, count) while split. * Default split characters are empty characters. */ template <class Func> void splitString( std::string_view str, const Func& func, const char* delimiter = " \t\r\n") { std::size_t startIndex = 0; std::size_t count = 0; while (startIndex < str.size()) { auto index = str.find_first_of(delimiter, startIndex); auto endIndex = (index == str.npos) ? str.size() : index; func(str.substr(startIndex, endIndex - startIndex), count); index = str.find_first_not_of(delimiter, endIndex); startIndex = (index == str.npos) ? str.size() : index; ++count; } } /** * Split string with specified characters. * Call func(parts, count) while split. * Single char version for better performance. */ template <class Func> void splitString(std::string_view str, const Func& func, char delimiter) { std::size_t startIndex = 0; std::size_t count = 0; while (startIndex < str.size()) { auto index = str.find_first_of(delimiter, startIndex); auto endIndex = (index == str.npos) ? str.size() : index; func(str.substr(startIndex, endIndex - startIndex), count); index = str.find_first_not_of(delimiter, endIndex); startIndex = (index == str.npos) ? str.size() : index; ++count; } } /** * Join arguments into string. * This function is very slow, don't call it where performance is important. */ template <class Delimiter, class... Args> std::string joinString(Delimiter&& delimiter, Args&&... args) { std::ostringstream stream; bool isFirst = true; auto func = [&stream, &isFirst, &delimiter](auto&& arg) { if (isFirst) { isFirst = false; } else { stream << delimiter; } stream << arg; return 0; }; int dummy[sizeof...(Args)] = { func(std::forward<Args>(args))... }; return stream.str(); } /** * Return sub string view that removes given prefix and suffix. */ template <bool TrimPrefix = true, bool TrimSuffix = true> std::string_view trimString(std::string_view str, const char* removes = " \t\r\n") { const char* ptr = str.begin(); const char* ptrEnd = str.end(); std::string_view rm(removes); if constexpr (TrimPrefix) { for (;ptr < ptrEnd && rm.find_first_of(*ptr) != rm.npos; ++ptr) { } } if constexpr (TrimSuffix) { for (;ptr < ptrEnd && rm.find_first_of(*(ptrEnd - 1)) != rm.npos;--ptrEnd) { } } return std::string_view(ptr, ptrEnd - ptr); } /** * Return sub string view that removes given prefix and suffix. * Single char version for better performance. */ template <bool TrimPrefix = true, bool TrimSuffix = true> std::string_view trimString(std::string_view str, char removes) { const char* ptr = str.begin(); const char* ptrEnd = str.end(); if constexpr (TrimPrefix) { for (;ptr < ptrEnd && *ptr == removes; ++ptr) { } } if constexpr (TrimSuffix) { for (;ptr < ptrEnd && *(ptrEnd - 1) == removes; --ptrEnd) { } } return std::string_view(ptr, ptrEnd - ptr); } /** * Convert integer to hex and write to string. * IntType can be any of int??_t and uint??_t. * Also see stackoverflow 5100718. */ template <class IntType, class StringType> void dumpIntToHex(IntType value, StringType& str) { static const constexpr char digits[] = "0123456789ABCDEF"; static const constexpr std::size_t hexLen = sizeof(IntType) * 2; for (std::size_t i = 0, j = (hexLen - 1) * 4; i < hexLen; ++i, j -= 4) { str.append(1, digits[(value >> j) & 0xf]); } } /** * Convert integer to decimal and write to string. * IntType can be any of int??_t and uint??_t. */ template <class IntType, class StringType> void dumpIntToDec(IntType value, StringType& str) { static const constexpr char digits[] = "0123456789"; if constexpr (std::numeric_limits<IntType>::is_signed) { if (value < 0) { str.append(1, '-'); } } std::size_t prevSize = str.size(); do { IntType rem = value % 10; value /= 10; str.append(1, digits[rem >= 0 ? rem : -rem]); } while (value != 0); std::reverse(str.begin() + prevSize, str.end()); } /** Convert bytes to hex and write to string */ template <class StringType> void dumpBytesToHex(const char* bytes, std::size_t length, StringType& str) { const char* start = bytes; const char* end = bytes + length; while (start < end) { std::uint8_t byte = static_cast<std::uint8_t>(*start++); dumpIntToHex(byte, str); } } /** * Convert dynamic size hex string to integer. * Return whether the coversion is successful. */ template <class IntType> bool loadIntFromHex(const char* hex, std::size_t hexLen, IntType& value) { using UnsignedIntType = std::make_unsigned_t<IntType>; std::uint8_t diff = 0; UnsignedIntType uvalue = 0; // avoid sanitizer warning: left shift of negative value const char* hexEnd = hex + hexLen; for (; hex < hexEnd; ++hex) { std::uint8_t c = static_cast<std::uint8_t>(*hex); if (c == 0) { return false; } else if ((diff = c - '0') <= 9) { uvalue = (uvalue << 4) | diff; } else if ((diff = c - 'a') <= 5) { uvalue = (uvalue << 4) | (diff + 0xa); } else if ((diff = c - 'A') <= 5) { uvalue = (uvalue << 4) | (diff + 0xa); } else { return false; } } value = static_cast<IntType>(uvalue); return true; } /** * Convert fixed size (sizeof(IntType)*2) hex string to integer. * Return whether the coversion is successful. */ template <class IntType> bool loadIntFromHex(const char* hex, IntType& value) { return loadIntFromHex<IntType>(hex, sizeof(IntType)*2, value); } /** * Convert decimal string to integer. * Return whether the coversion is successful. * Notice convert minus decimal string to unsigned integer is an error, * but overflow isn't an error (the overhead of overflow detection is high). */ template <class IntType> bool loadIntFromDec(const char* dec, std::size_t decLength, IntType& value) { const char* decEnd = dec + decLength; bool minus = false; if (CPV_UNLIKELY(dec < decEnd && *dec == '-')) { minus = true; ++dec; } std::uint8_t diff = 0; value = 0; while (CPV_LIKELY(dec < decEnd)) { if (CPV_LIKELY((diff = *dec - '0') <= 9)) { value *= 10; value += diff; ++dec; } else { return false; } } if constexpr (!std::numeric_limits<IntType>::is_signed) { if (minus) { return false; } } else if (minus) { value = -value; } return true; } /** * Convert hex string to bytes. * Return whether the coversion is successful. */ template <class StringType> bool loadBytesFromHex(const char* hex, std::size_t hexLength, StringType& str) { const char* start = hex; const char* end = hex + hexLength; char c = 0; while (start < end && *start != 0) { if (!loadIntFromHex<char>(start, c)) { return false; } str.append(1, c); start += 2; } return start == end; } /** Compare two string case insensitive */ bool caseInsensitiveEquals(std::string_view a, std::string_view b); /** Get size of string contents */ template <class StringType> std::size_t sizeofString(StringType&& str) { return std::size(str); } /** Get size of c string contents (exclude tailing zero) */ template <std::size_t Size> std::size_t sizeofString(const char(&)[Size]) { static_assert(Size > 0, "size of c string should not be 0"); return Size - 1; } /** Construct string with fixed size, string may contains \x00 */ template <std::size_t Size> std::string makeBinaryString(const char(&str)[Size]) { static_assert(Size > 0, "string must be null terminated"); return std::string(str, Size - 1); } }
#include "strUtil.h" void test() { cpv::startsWith("test", "tes"); cpv::endsWith("test", "tes"); // split by chars std::vector<std::string> results; std::size_t countRecord = 0; std::string str("aaa \tb c\nd eee"); cpv::splitString(str, [&results, &countRecord](auto parts, auto count) { ASSERT_EQ(countRecord, count); ++countRecord; results.emplace_back(parts); }); std::string a = cpv::joinString(" ", "a", 123, "asd"); cpv::trimString<false, true>(" \t\n\rab c\r\n \t")); // " \t\n\rab c" std::string str; cpv::dumpIntToHex<std::uint8_t>(0x7f, str); cpv::dumpIntToDec<std::int8_t>(-128, str); cpv::dumpBytesToHex("abc", 3, str); std::int32_t value = 0; cpv::loadIntFromHex("EDCBa988", value); cpv::loadBytesFromHex("616263", 6, str); cpv::caseInsensitiveEquals(std::string("abc"), std::string("Abc")); cpv::makeBinaryString("abc\x00""def"); }

std::optional<int> getResult() {
if (/* some condition */) {
return 42;
}
return std::nullopt;
}

s.substr(0, str.size()) == str
s.substr(str.size()) == str
std::stoi/stof/stod

// 随机字符串生成
inline std::string randomStringGenerator(const int len)
{
std::string res;
static const char alphanum[] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";

for (int i = 0; i < len; ++i)
res += alphanum[((size_t)std::rand() % (sizeof(alphanum) - 1))];
return res;
}

inline bool replace(std::string & input_str, const std::string & from, const std::string & to) { bool has_from = false; size_t start_pos = input_str.find(from); while (start_pos != std::string::npos) { has_from = true; input_str.replace(start_pos, from.length(), to); start_pos = input_str.find(from); } return has_from; }

C++ UTF-8编解码-CSDN博客


创作不易,小小的支持一下吧!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 6:05:40

工业SPI通信物理隔离设计实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/2 6:05:18

PLFM_RADAR:FPGA+STM32异构架构的线性调频雷达系统设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/2 6:04:26

基于MAX14431BAEE+与STM32L031K6的SPI隔离通信方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/2 6:03:50

工业SPI隔离设计:MAX14431BAEE+与PIC18F67K40实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/2 6:02:13

PLFM_RADAR:用雷达思维重构平台监控,从噪声中锁定真实故障

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华