From 625b4f2d9fe9804b7c3fe726c68e4cc77533a0b9 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Fri, 26 Jan 2024 10:02:15 +0100 Subject: [PATCH] Core/StringExt: Add Substring family of function (unicode-aware) --- include/Nazara/Core/StringExt.hpp | 3 ++ include/Nazara/Core/StringExt.inl | 6 ++++ src/Nazara/Core/StringExt.cpp | 29 +++++++++++++++++++ tests/UnitTests/Engine/Core/StringExtTest.cpp | 9 ++++++ 4 files changed, 47 insertions(+) diff --git a/include/Nazara/Core/StringExt.hpp b/include/Nazara/Core/StringExt.hpp index eb337224f..0f52e5a73 100644 --- a/include/Nazara/Core/StringExt.hpp +++ b/include/Nazara/Core/StringExt.hpp @@ -48,6 +48,9 @@ namespace Nz template std::basic_string& ReplaceStr(std::basic_string& str, const T* from, const T* to); template std::basic_string& ReplaceStr(std::basic_string& str, std::basic_string_view from, std::basic_string_view to); + inline std::string_view Substring(std::string_view str, std::size_t index, UnicodeAware); + NAZARA_CORE_API std::string_view Substring(std::string_view str, std::size_t index, std::size_t count, UnicodeAware); + inline bool StartsWith(std::string_view str, std::string_view s); NAZARA_CORE_API bool StartsWith(std::string_view lhs, std::string_view rhs, CaseIndependent); NAZARA_CORE_API bool StartsWith(std::string_view lhs, std::string_view rhs, UnicodeAware); diff --git a/include/Nazara/Core/StringExt.inl b/include/Nazara/Core/StringExt.inl index df3b16019..50e3c12c1 100644 --- a/include/Nazara/Core/StringExt.inl +++ b/include/Nazara/Core/StringExt.inl @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace Nz @@ -109,6 +110,11 @@ namespace Nz return str; } + std::string_view Substring(std::string_view str, std::size_t index, UnicodeAware) + { + return Substring(str, index, std::numeric_limits::max(), UnicodeAware{}); + } + inline bool StartsWith(std::string_view str, std::string_view s) { #if NAZARA_CPP_VER >= NAZARA_CPP20 diff --git a/src/Nazara/Core/StringExt.cpp b/src/Nazara/Core/StringExt.cpp index 7ac78e762..fa85423c1 100644 --- a/src/Nazara/Core/StringExt.cpp +++ b/src/Nazara/Core/StringExt.cpp @@ -389,6 +389,35 @@ namespace Nz return str; } + std::string_view Substring(std::string_view str, std::size_t index, std::size_t count, UnicodeAware) + { + const char* start = str.data(); + const char* end = start + str.size(); + try + { + utf8::advance(start, index, end); + } + catch (const utf8::not_enough_room&) + { + return {}; + } + + if (count == std::numeric_limits::max()) + return str.substr(start - str.data()); + + const char* to = start; + try + { + utf8::advance(to, count, end); + } + catch (const utf8::not_enough_room&) + { + return str.substr(start - str.data()); + } + + return std::string_view(start, to - start); + } + bool StartsWith(std::string_view lhs, std::string_view rhs, CaseIndependent) { NAZARA_USE_ANONYMOUS_NAMESPACE diff --git a/tests/UnitTests/Engine/Core/StringExtTest.cpp b/tests/UnitTests/Engine/Core/StringExtTest.cpp index b7f467b07..66c8736cd 100644 --- a/tests/UnitTests/Engine/Core/StringExtTest.cpp +++ b/tests/UnitTests/Engine/Core/StringExtTest.cpp @@ -112,6 +112,15 @@ SCENARIO("String", "[CORE][STRING]") REQUIRE(Nz::ReplaceStr(str, "Unreal Reality", "Ungine") == "Ungine"); } + WHEN("Getting substring of unicode strings") + { + std::string_view str = "\u00E0\u00E9\u00E7\u0153\u00C2\u5B98"; + CHECK(Nz::Substring(str, 0, 150, Nz::UnicodeAware{}) == "\u00E0\u00E9\u00E7\u0153\u00C2\u5B98"); + CHECK(Nz::Substring(str, 1, Nz::UnicodeAware{}) == "\u00E9\u00E7\u0153\u00C2\u5B98"); + CHECK(Nz::Substring(str, 1, 2, Nz::UnicodeAware{}) == "\u00E9\u00E7"); + CHECK(Nz::Substring(str, 1, 10, Nz::UnicodeAware{}) == "\u00E9\u00E7\u0153\u00C2\u5B98"); + } + WHEN("Checking if string starts with") { CHECK(Nz::StartsWith("Nazara Engine", ""));