refactor: refactor string helper for UTF8 string

This commit is contained in:
yyc12345 2024-06-28 14:44:39 +08:00
parent 91ba0c22d6
commit 44dbbb1c99
3 changed files with 93 additions and 71 deletions

View File

@ -1,9 +1,12 @@
#include "StringHelper.hpp" #include "StringHelper.hpp"
#include "EncodingHelper.hpp"
#include <algorithm> #include <algorithm>
namespace YYCC::StringHelper { namespace YYCC::StringHelper {
bool Printf(std::string& strl, const char* format, ...) { #pragma region Printf VPrintf
bool Printf(yycc_u8string& strl, const yycc_char8_t* format, ...) {
va_list argptr; va_list argptr;
va_start(argptr, format); va_start(argptr, format);
bool ret = VPrintf(strl, format, argptr); bool ret = VPrintf(strl, format, argptr);
@ -11,7 +14,7 @@ namespace YYCC::StringHelper {
return ret; return ret;
} }
bool VPrintf(std::string& strl, const char* format, va_list argptr) { bool VPrintf(yycc_u8string& strl, const yycc_char8_t* format, va_list argptr) {
va_list args1; va_list args1;
va_copy(args1, argptr); va_copy(args1, argptr);
va_list args2; va_list args2;
@ -19,7 +22,12 @@ namespace YYCC::StringHelper {
// the return value is desired char count without NULL terminal. // the return value is desired char count without NULL terminal.
// minus number means error // minus number means error
int count = std::vsnprintf(nullptr, 0, format, args1); int count = std::vsnprintf(
nullptr,
0,
EncodingHelper::ToNative(format),
args1
);
if (count < 0) { if (count < 0) {
// invalid length returned by vsnprintf. // invalid length returned by vsnprintf.
return false; return false;
@ -31,7 +39,12 @@ namespace YYCC::StringHelper {
// because std::vsnprintf only can write "buf_size - 1" chars with a trailing NULL. // because std::vsnprintf only can write "buf_size - 1" chars with a trailing NULL.
// however std::vsnprintf already have a trailing NULL, so we plus 1 for it. // however std::vsnprintf already have a trailing NULL, so we plus 1 for it.
strl.resize(count); strl.resize(count);
int write_result = std::vsnprintf(strl.data(), strl.size() + 1, format, args2); int write_result = std::vsnprintf(
EncodingHelper::ToNative(strl.data()),
strl.size() + 1,
EncodingHelper::ToNative(format),
args2
);
va_end(args2); va_end(args2);
if (write_result < 0 || write_result > count) { if (write_result < 0 || write_result > count) {
@ -42,9 +55,8 @@ namespace YYCC::StringHelper {
return true; return true;
} }
yycc_u8string Printf(const yycc_char8_t* format, ...) {
std::string Printf(const char* format, ...) { yycc_u8string ret;
std::string ret;
va_list argptr; va_list argptr;
va_start(argptr, format); va_start(argptr, format);
@ -54,8 +66,8 @@ namespace YYCC::StringHelper {
return ret; return ret;
} }
std::string VPrintf(const char* format, va_list argptr) { yycc_u8string VPrintf(const yycc_char8_t* format, va_list argptr) {
std::string ret; yycc_u8string ret;
va_list argcpy; va_list argcpy;
va_copy(argcpy, argptr); va_copy(argcpy, argptr);
@ -65,28 +77,32 @@ namespace YYCC::StringHelper {
return ret; return ret;
} }
void Replace(std::string& strl, const char* _from_strl, const char* _to_strl) { #pragma endregion
#pragma region Replace
void Replace(yycc_u8string& strl, const yycc_char8_t* _from_strl, const yycc_char8_t* _to_strl) {
// Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string // Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string
// check requirements // check requirements
// from string and to string should not be nullptr. // from string and to string should not be nullptr.
if (_from_strl == nullptr || _to_strl == nullptr) return; if (_from_strl == nullptr || _to_strl == nullptr) return;
// from string should not be empty // from string should not be empty
std::string from_strl(_from_strl); yycc_u8string from_strl(_from_strl);
std::string to_strl(_to_strl); yycc_u8string to_strl(_to_strl);
if (from_strl.empty()) return; if (from_strl.empty()) return;
// start replace one by one // start replace one by one
size_t start_pos = 0; size_t start_pos = 0;
while ((start_pos = strl.find(from_strl, start_pos)) != std::string::npos) { while ((start_pos = strl.find(from_strl, start_pos)) != yycc_u8string::npos) {
strl.replace(start_pos, from_strl.size(), to_strl); strl.replace(start_pos, from_strl.size(), to_strl);
start_pos += to_strl.size(); // In case 'to' contains 'from', like replacing 'x' with 'yx' start_pos += to_strl.size(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
} }
} }
std::string Replace(const char* _strl, const char* _from_strl, const char* _to_strl) { yycc_u8string Replace(const yycc_char8_t* _strl, const yycc_char8_t* _from_strl, const yycc_char8_t* _to_strl) {
// prepare result // prepare result
std::string strl; yycc_u8string strl;
// if given string is not nullptr, assign it and process it. // if given string is not nullptr, assign it and process it.
if (_strl != nullptr) { if (_strl != nullptr) {
strl = _strl; strl = _strl;
@ -96,13 +112,17 @@ namespace YYCC::StringHelper {
return strl; return strl;
} }
std::string Join(JoinDataProvider fct_data, const char* decilmer) { #pragma endregion
std::string ret;
#pragma region Join
yycc_u8string Join(JoinDataProvider fct_data, const yycc_char8_t* decilmer) {
yycc_u8string ret;
bool is_first = true; bool is_first = true;
const char* element; yycc_u8string_view element;
// fetch element // fetch element
while ((element = fct_data()) != nullptr) { while (fct_data(element)) {
// insert decilmer // insert decilmer
if (is_first) is_first = false; if (is_first) is_first = false;
else { else {
@ -111,42 +131,46 @@ namespace YYCC::StringHelper {
ret.append(decilmer); ret.append(decilmer);
} }
// insert element // insert element if it is not empty
ret.append(element); if (!element.empty())
ret.append(element);
} }
return ret; return ret;
} }
std::string Join(const std::vector<std::string>& data, const char* decilmer, bool reversed) { yycc_u8string Join(const std::vector<yycc_u8string>& data, const yycc_char8_t* decilmer, bool reversed) {
if (reversed) { if (reversed) {
auto iter = data.crbegin(); auto iter = data.crbegin();
auto stop = data.crend(); auto stop = data.crend();
return Join([&iter, &stop]() -> const char* { return Join([&iter, &stop](yycc_u8string_view& view) -> bool {
// if we reach tail, return nullptr // if we reach tail, return false
if (iter == stop) return nullptr; if (iter == stop) return false;
// otherwise fetch data, inc iterator and return. // otherwise fetch data, inc iterator and return.
const char* ret = iter->c_str(); view = *iter;
++iter; ++iter;
return ret; return true;
}, decilmer); }, decilmer);
} else { } else {
auto iter = data.cbegin(); auto iter = data.cbegin();
auto stop = data.cend(); auto stop = data.cend();
return Join([&iter, &stop]() -> const char* { return Join([&iter, &stop](yycc_u8string_view& view) -> bool {
// if we reach tail, return nullptr // if we reach tail, return nullptr
if (iter == stop) return nullptr; if (iter == stop) return false;
// otherwise fetch data, inc iterator and return. // otherwise fetch data, inc iterator and return.
const char* ret = iter->c_str(); view = *iter;
++iter; ++iter;
return ret; return true;
}, decilmer); }, decilmer);
} }
} }
#pragma endregion
#pragma region Upper Lower
template<bool bIsToLower> template<bool bIsToLower>
void GeneralStringLowerUpper(std::string& strl) { void GeneralStringLowerUpper(yycc_u8string& strl) {
// References: // References:
// https://en.cppreference.com/w/cpp/algorithm/transform // https://en.cppreference.com/w/cpp/algorithm/transform
// https://en.cppreference.com/w/cpp/string/byte/tolower // https://en.cppreference.com/w/cpp/string/byte/tolower
@ -159,43 +183,47 @@ namespace YYCC::StringHelper {
); );
} }
std::string Lower(const char* strl) { yycc_u8string Lower(const yycc_char8_t* strl) {
std::string ret; yycc_u8string ret;
if (strl == nullptr) return ret; if (strl == nullptr) return ret;
else ret = strl; else ret = strl;
Lower(ret); Lower(ret);
return ret; return ret;
} }
void Lower(std::string& strl) { void Lower(yycc_u8string& strl) {
GeneralStringLowerUpper<true>(strl); GeneralStringLowerUpper<true>(strl);
} }
std::string Upper(const char* strl) { yycc_u8string Upper(const yycc_char8_t* strl) {
// same as Lower, just replace char transform function. // same as Lower, just replace char transform function.
std::string ret; yycc_u8string ret;
if (strl == nullptr) return ret; if (strl == nullptr) return ret;
else ret = strl; else ret = strl;
Upper(ret); Upper(ret);
return ret; return ret;
} }
void Upper(std::string& strl) { void Upper(yycc_u8string& strl) {
GeneralStringLowerUpper<false>(strl); GeneralStringLowerUpper<false>(strl);
} }
std::vector<std::string> Split(const char* _strl, const char* _decilmer) { #pragma endregion
#pragma region Split
std::vector<yycc_u8string> Split(const yycc_char8_t* _strl, const yycc_char8_t* _decilmer) {
// Reference: // Reference:
// https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c // https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
// prepare return value // prepare return value
std::vector<std::string> elems; std::vector<yycc_u8string> elems;
// if the string need to be splitted is nullptr, return empty result. // if the string need to be splitted is nullptr, return empty result.
if (_strl == nullptr) return elems; if (_strl == nullptr) return elems;
std::string strl(_strl); yycc_u8string strl(_strl);
// if decilmer is nullptr, or decilmer is zero length, return original string // if decilmer is nullptr, or decilmer is zero length, return original string
std::string decilmer; yycc_u8string decilmer;
if (_decilmer == nullptr || (decilmer = _decilmer, decilmer.empty())) { if (_decilmer == nullptr || (decilmer = _decilmer, decilmer.empty())) {
elems.push_back(strl); elems.push_back(strl);
return elems; return elems;
@ -203,7 +231,7 @@ namespace YYCC::StringHelper {
// start spliting // start spliting
std::size_t previous = 0, current; std::size_t previous = 0, current;
while ((current = strl.find(decilmer.c_str(), previous)) != std::string::npos) { while ((current = strl.find(decilmer.c_str(), previous)) != yycc_u8string::npos) {
elems.push_back(strl.substr(previous, current - previous)); elems.push_back(strl.substr(previous, current - previous));
previous = current + decilmer.size(); previous = current + decilmer.size();
} }
@ -214,4 +242,7 @@ namespace YYCC::StringHelper {
return elems; return elems;
} }
#pragma endregion
} }

View File

@ -8,21 +8,22 @@
namespace YYCC::StringHelper { namespace YYCC::StringHelper {
bool Printf(std::string& strl, const char* format, ...); bool Printf(yycc_u8string& strl, const yycc_char8_t* format, ...);
bool VPrintf(std::string& strl, const char* format, va_list argptr); bool VPrintf(yycc_u8string& strl, const yycc_char8_t* format, va_list argptr);
yycc_u8string Printf(const yycc_char8_t* format, ...);
yycc_u8string VPrintf(const yycc_char8_t* format, va_list argptr);
std::string Printf(const char* format, ...); void Replace(yycc_u8string& strl, const yycc_char8_t* _from_strl, const yycc_char8_t* _to_strl);
std::string VPrintf(const char* format, va_list argptr); yycc_u8string Replace(const yycc_char8_t* _strl, const yycc_char8_t* _from_strl, const yycc_char8_t* _to_strl);
void Replace(std::string& strl, const char* _from_strl, const char* _to_strl);
std::string Replace(const char* _strl, const char* _from_strl, const char* _to_strl);
/** /**
* @brief The data provider of general Join function. * @brief The data provider of general Join function.
* This function pointer return non-null string pointer to represent a element of joined series. * For the implementation of this function:
* otherwise return nullptr to terminate the joining process. * Function return true to continue join. otherwise return false to terminate join.
* The argument assigned in the calling returning false is not included.
* During calling, implementation should assign the string view to the string need to be joined in given argument.
*/ */
using JoinDataProvider = std::function<const char* ()>; using JoinDataProvider = std::function<bool(yycc_u8string_view&)>;
/** /**
* @brief General Join function. * @brief General Join function.
* @details This function use function pointer as a general data provider interface, * @details This function use function pointer as a general data provider interface,
@ -31,7 +32,7 @@ namespace YYCC::StringHelper {
* @param decilmer[in] The decilmer. * @param decilmer[in] The decilmer.
* @return A std::string instance which containing the join result. * @return A std::string instance which containing the join result.
*/ */
std::string Join(JoinDataProvider fct_data, const char* decilmer); yycc_u8string Join(JoinDataProvider fct_data, const yycc_char8_t* decilmer);
/** /**
* @brief Specialized Join function for common used container. * @brief Specialized Join function for common used container.
* @param data * @param data
@ -39,22 +40,12 @@ namespace YYCC::StringHelper {
* @param reversed * @param reversed
* @return * @return
*/ */
std::string Join(const std::vector<std::string>& data, const char* decilmer, bool reversed = false); yycc_u8string Join(const std::vector<yycc_u8string>& data, const yycc_char8_t* decilmer, bool reversed = false);
/** yycc_u8string Lower(const yycc_char8_t* strl);
* @brief Transform string to lower. void Lower(yycc_u8string& strl);
* @param strl yycc_u8string Upper(const yycc_char8_t* strl);
* @return void Upper(yycc_u8string& strl);
*/
std::string Lower(const char* strl);
void Lower(std::string& strl);
/**
* @brief Transform string to upper.
* @param strl
* @return
*/
std::string Upper(const char* strl);
void Upper(std::string& strl);
/** /**
* @brief General Split function. * @brief General Split function.
@ -67,5 +58,5 @@ namespace YYCC::StringHelper {
* It can works in most toy cases but not suit for high performance scenario. * It can works in most toy cases but not suit for high performance scenario.
* Also, this function will produce a copy of original string because it is not zero copy. * Also, this function will produce a copy of original string because it is not zero copy.
*/ */
std::vector<std::string> Split(const char* _strl, const char* _decilmer); std::vector<yycc_u8string> Split(const yycc_char8_t* _strl, const yycc_char8_t* _decilmer);
} }

View File

@ -2,8 +2,8 @@
#include "YYCCInternal.hpp" #include "YYCCInternal.hpp"
#include "StringHelper.hpp"
#include "EncodingHelper.hpp" #include "EncodingHelper.hpp"
#include "StringHelper.hpp"
#include "ConsoleHelper.hpp" #include "ConsoleHelper.hpp"
#include "COMHelper.hpp" #include "COMHelper.hpp"
#include "DialogHelper.hpp" #include "DialogHelper.hpp"