From b8a56efd7cc4d578f02111629051adf979e16423 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Wed, 22 May 2024 13:42:43 +0800 Subject: [PATCH] feat: finish string helper. - finish Split() in string helper. - make complement to testbench test code. --- src/IOHelper.cpp | 1 + src/IOHelper.hpp | 2 +- src/ParserHelper.hpp | 2 -- src/StringHelper.cpp | 43 +++++++++++++++++-------------------- src/StringHelper.hpp | 6 ++++-- testbench/main.cpp | 51 ++++++++++++++++++++++++++++++++------------ 6 files changed, 63 insertions(+), 42 deletions(-) diff --git a/src/IOHelper.cpp b/src/IOHelper.cpp index 3929419..0fae29d 100644 --- a/src/IOHelper.cpp +++ b/src/IOHelper.cpp @@ -4,6 +4,7 @@ #include "EncodingHelper.hpp" #include #include +#include namespace YYCC::IOHelper { diff --git a/src/IOHelper.hpp b/src/IOHelper.hpp index 8a28424..d1803f5 100644 --- a/src/IOHelper.hpp +++ b/src/IOHelper.hpp @@ -2,7 +2,7 @@ #include "YYCCInternal.hpp" #if YYCC_OS == YYCC_OS_WINDOWS -#include +#include namespace YYCC::IOHelper { diff --git a/src/ParserHelper.hpp b/src/ParserHelper.hpp index 90b3e83..74f4349 100644 --- a/src/ParserHelper.hpp +++ b/src/ParserHelper.hpp @@ -6,7 +6,5 @@ namespace YYCC::ParserHelper { bool Parse(const std::string& strl, int& ret, int base = 10); int Parse(const std::string& strl, int base = 10); - bool ToString(int val, std::string& ret, int base = 10); - std::string ToString(int val, int base = 10); } diff --git a/src/StringHelper.cpp b/src/StringHelper.cpp index ea4dd50..7703e25 100644 --- a/src/StringHelper.cpp +++ b/src/StringHelper.cpp @@ -98,7 +98,7 @@ namespace YYCC::StringHelper { const char* ret = iter->c_str(); ++iter; return ret; - }, decilmer); + }, decilmer); } else { auto iter = data.cbegin(); auto stop = data.cend(); @@ -109,7 +109,7 @@ namespace YYCC::StringHelper { const char* ret = iter->c_str(); ++iter; return ret; - }, decilmer); + }, decilmer); } } @@ -119,7 +119,7 @@ namespace YYCC::StringHelper { // https://en.cppreference.com/w/cpp/algorithm/transform // https://en.cppreference.com/w/cpp/string/byte/tolower std::transform( - strl.cbegin(), strl.cend(), strl.begin(), + strl.cbegin(), strl.cend(), strl.begin(), [](unsigned char c) -> char { if constexpr (bIsToLower) return std::tolower(c); else return std::toupper(c); @@ -153,33 +153,30 @@ namespace YYCC::StringHelper { } std::vector Split(const char* _strl, const char* _decilmer) { - std::vector elems; + // Reference: + // https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c - // check whether string and decilmer are nullptr - std::string strl, decilmer; - if (_strl == nullptr || _decilmer == nullptr) - return elems; - else { - strl = _strl; - decilmer = _decilmer; - } - // if no decilmer, return the whole string as the only one element of result. - if (decilmer.empty()) { + // prepare return value + std::vector elems; + + // if the string need to be splitted is nullptr, return empty result. + if (_strl == nullptr) return elems; + std::string strl(_strl); + // if decilmer is nullptr, or decilmer is zero length, return original string + std::string decilmer; + if (_decilmer == nullptr || (decilmer = _decilmer, decilmer.empty())) { elems.push_back(strl); return elems; } - + // start spliting - std::size_t previous = 0; - std::size_t current = strl.find(decilmer.c_str()); - while (current != std::string::npos) { - if (current >= previous) { - elems.push_back(strl.substr(previous, current - previous)); - } + std::size_t previous = 0, current; + while ((current = strl.find(decilmer.c_str(), previous)) != std::string::npos) { + elems.push_back(strl.substr(previous, current - previous)); previous = current + decilmer.size(); - current = strl.find(decilmer, previous); } - if (previous != strl.size()) { + // try insert last part but prevent possible out of range exception + if (previous <= strl.size()) { elems.push_back(strl.substr(previous)); } return elems; diff --git a/src/StringHelper.hpp b/src/StringHelper.hpp index eeef822..32726c8 100644 --- a/src/StringHelper.hpp +++ b/src/StringHelper.hpp @@ -53,8 +53,10 @@ namespace YYCC::StringHelper { /** * @brief General Split function. - * @param _strl - * @param _decilmer + * @param _strl[in] The string need to be splitting. + * If this is nullptr, the result will be empty. + * @param _decilmer[in] The decilmer for splitting. + * If decilmer is nullptr or zero length, the result will only have 1 element which is original string. * @return * @remarks This function may be low performance because it just a homebrew Split functon. * It can works in most toy cases but not suit for high performance scenario. diff --git a/testbench/main.cpp b/testbench/main.cpp index 003495c..91b0391 100644 --- a/testbench/main.cpp +++ b/testbench/main.cpp @@ -3,6 +3,15 @@ namespace Testbench { + static void Assert(bool condition, const char* description) { + if (condition) { + YYCC::TerminalHelper::FPrintf(stdout, YYCC_TERMCOL_LIGHT_GREEN(u8"OK: %s\n"), description); + } else { + YYCC::TerminalHelper::FPrintf(stdout, YYCC_TERMCOL_LIGHT_RED(u8"Failed: %s\n"), description); + std::abort(); + } + } + static void TerminalTestbench() { YYCC::TerminalHelper::EnsureTerminalUTF8(stdout); YYCC::TerminalHelper::FPuts(u8"你好世界\n", stdout); @@ -11,22 +20,36 @@ namespace Testbench { } static void StringTestbench() { - YYCC::TerminalHelper::FPuts( - YYCC::StringHelper::Printf(u8"Translation: %s == %s\n", u8"Hello World", u8"你好世界").c_str(), - stdout - ); + auto test_printf = YYCC::StringHelper::Printf(u8"%s == %s", u8"Hello World", u8"你好世界"); + Assert(test_printf == u8"Hello World == 你好世界", "YYCC::StringHelper::Printf"); + + auto test_lower = YYCC::StringHelper::Lower("LOWER"); + Assert(test_lower == "lower", "YYCC::StringHelper::Lower"); + auto test_upper = YYCC::StringHelper::Upper("upper"); + Assert(test_upper == "UPPER", "YYCC::StringHelper::Upper"); - std::string test_string(u8"UPPER -> lower\n"); - YYCC::TerminalHelper::FPuts(test_string.c_str(), stdout); - YYCC::TerminalHelper::FPuts(YYCC::StringHelper::Lower(test_string.c_str()).c_str(), stdout); - YYCC::TerminalHelper::FPuts(YYCC::StringHelper::Upper(test_string.c_str()).c_str(), stdout); - - std::vector test_container { - "test1", "test2", "test3", "test4" + + std::vector test_join_container { + "", "1", "2", "" }; - YYCC::TerminalHelper::FPuts(YYCC::StringHelper::Join(test_container, ", ").c_str(), stdout); - std::string test_split(", 1, 3, 5, 7, 9, "); - YYCC::TerminalHelper::FPuts(YYCC::StringHelper::Join(YYCC::StringHelper::Split(test_split.c_str(), ", "), " -> ").c_str(), stdout); + auto test_join = YYCC::StringHelper::Join(test_join_container, ", "); + Assert(test_join == ", 1, 2, ", "YYCC::StringHelper::Join"); + test_join = YYCC::StringHelper::Join(test_join_container, ", ", true); + Assert(test_join == ", 2, 1, ", "YYCC::StringHelper::Join"); + + auto test_split = YYCC::StringHelper::Split(", 1, 2, ", ", "); + Assert(test_split.size() == 4u, "YYCC::StringHelper::Split"); + Assert(test_split[0] == "", "YYCC::StringHelper::Split"); + Assert(test_split[1] == "1", "YYCC::StringHelper::Split"); + Assert(test_split[2] == "2", "YYCC::StringHelper::Split"); + Assert(test_split[3] == "", "YYCC::StringHelper::Split"); + test_split = YYCC::StringHelper::Split("test", "-"); + Assert(test_split.size() == 1u, "YYCC::StringHelper::Split"); + Assert(test_split[0] == "test", "YYCC::StringHelper::Split"); + test_split = YYCC::StringHelper::Split("test", ""); + Assert(test_split.size() == 1u, "YYCC::StringHelper::Split"); + Assert(test_split[0] == "test", "YYCC::StringHelper::Split"); + } }