diff --git a/CMakeLists.txt b/CMakeLists.txt
index af6639f..4d65535 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@ include(FetchContent)
project(
simstr
- VERSION 1.4.0
+ VERSION 1.5.0
DESCRIPTION "Yet another modern C++ string library"
HOMEPAGE_URL "https://github.com/orefkov/simstr"
LANGUAGES CXX
@@ -116,7 +116,7 @@ if(SIMSTR_BUILD_TESTS)
googletest
# Specify the commit you depend on and update it regularly.
URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.zip
- FIND_PACKAGE_ARGS NAMES GTest 1.17.0
+ FIND_PACKAGE_ARGS NAMES "GTest 1.17.0"
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt FALSE CACHE BOOL "" FORCE)
@@ -134,7 +134,7 @@ function(GBencmark)
googlebench
# Specify the commit you depend on and update it regularly.
URL https://github.com/google/benchmark/archive/refs/tags/v1.9.4.zip
- FIND_PACKAGE_ARGS NAMES benchmark 1.9.4
+ FIND_PACKAGE_ARGS NAMES "benchmark 1.9.4"
)
set(BENCHMARK_ENABLE_TESTING OFF)
set(BENCHMARK_ENABLE_LTO OFF)
diff --git a/docs/Doxyfile b/docs/Doxyfile
index b5923db..96c6834 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = "simstr"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.4.0
+PROJECT_NUMBER = 1.5.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewers a
diff --git a/docs/Doxyfile_ru b/docs/Doxyfile_ru
index 82a05c3..e88e5db 100644
--- a/docs/Doxyfile_ru
+++ b/docs/Doxyfile_ru
@@ -48,7 +48,7 @@ PROJECT_NAME = "simstr"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.4.0
+PROJECT_NUMBER = 1.5.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewers a
diff --git a/include/simstr/simple_unicode.h b/include/simstr/simple_unicode.h
index d047d08..d7328de 100644
--- a/include/simstr/simple_unicode.h
+++ b/include/simstr/simple_unicode.h
@@ -1,6 +1,6 @@
/*
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
- * ver. 1.0
+ * ver. 1.5.0
*/
#pragma once
diff --git a/include/simstr/sstring.h b/include/simstr/sstring.h
index 511b68f..a06e3b9 100644
--- a/include/simstr/sstring.h
+++ b/include/simstr/sstring.h
@@ -1,9 +1,9 @@
/*
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
- * ver. 1.4.0
+ * ver. 1.5.0
* Классы для работы со строками
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
-* ver. 1.4.0
+* ver. 1.5.0
* Classes for working with strings
*/
@@ -314,7 +314,13 @@ public:
return {};
}
#endif
- return impl_to_double(ptr, ptr + len);
+ if constexpr (sizeof(K) == 1) {
+ return impl_to_double((const char*)ptr, (const char*)ptr + len);
+ } else if constexpr (sizeof(K) == 2) {
+ return impl_to_double((const char16_t*)ptr, (const char16_t*)ptr + len);
+ } else {
+ return impl_to_double((const char32_t*)ptr, (const char32_t*)ptr + len);
+ }
}
/*!
* @ru @brief Преобразовать строку в double.
diff --git a/include/simstr/strexpr.h b/include/simstr/strexpr.h
index 4fa4991..aa91382 100644
--- a/include/simstr/strexpr.h
+++ b/include/simstr/strexpr.h
@@ -1,5 +1,5 @@
/*
- * ver. 1.4.0
+ * ver. 1.5.0
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
* База для строковых конкатенаций через выражения времени компиляции
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
@@ -3282,7 +3282,7 @@ public:
return {};
}
double d{};
- if (std::from_chars(ptr, ptr + len, d).ec == std::errc{}) {
+ if (std::from_chars((const u8s*)ptr, (const u8s*)ptr + len, d).ec == std::errc{}) {
return d;
}
return {};
@@ -4477,32 +4477,20 @@ constexpr auto e_repl(A&& w, T&& p, X&& r) {
/*!
* @ingroup StrExprs
- * @ru @brief Строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки.
+ * @ru @brief Строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки на другую строку.
* @tparam K - тип строки.
- * @details `e_repl` позволяет заменять только с использование строковых литералов.
- * В случае, когда искомая подстрока или строка замены не известны при компиляции, и задаются в runtime,
- * следует использовать этот тип, например:
- * @en @brief A string expression that generates a string replacing all occurrences of the given substring.
+ * @en @brief A string expression that generates a string replacing all occurrences of the given substring to another string.
* @tparam K - string type.
- * @details `e_repl` only allows replacement using string literals.
- * In the case when the required substring or replacement string is not known at compilation, and is set at runtime,
- * this type should be used, for example:
- * @~
- * ```cpp
- * stringa result = "" + expr_replaced{source, pattern, repl} + "";
- * ```
*/
-template
+template
struct expr_replaced : expr_to_std_string> {
using symb_type = K;
using my_type = expr_replaced;
str_src what;
const str_src pattern;
- mutable K* replStart;
- mutable size_t replLen;
+ const str_src repl;
mutable find_all_container matches_;
mutable size_t last_;
- const E& expr;
/*!
* @ru @brief Конструктор.
* @param w - исходная строка.
@@ -4513,20 +4501,17 @@ struct expr_replaced : expr_to_std_string> {
* @param p - the searched substring.
* @param r - replacement string.
*/
- constexpr expr_replaced(str_src w, str_src p, const K* r, size_t rl, const E& e) : what(w), pattern(p), replStart(const_cast(r)), replLen(rl), expr(e) {}
+ constexpr expr_replaced(str_src w, str_src p, str_src r) : what(w), pattern(p), repl(r) {}
constexpr size_t length() const {
- size_t l = what.length(), plen = pattern.length();
- if constexpr (!std::is_same_v) {
- replLen = expr.length();
- }
- if (!plen || plen == replLen) {
+ size_t l = what.length(), plen = pattern.length(), rlen = repl.length();
+ if (!plen || plen == rlen) {
return l;
}
what.find_all_to(matches_, pattern.symbols(), plen, 0, FIND_CACHE_SIZE);
if (matches_.added_) {
last_ = matches_.positions_[matches_.added_ - 1] + plen;
- l += int(replLen - plen) * matches_.added_;
+ l += int(rlen - plen) * matches_.added_;
if (matches_.added_ == FIND_CACHE_SIZE) {
for (;;) {
@@ -4535,7 +4520,7 @@ struct expr_replaced : expr_to_std_string> {
break;
}
last_ = next + plen;
- l += replLen - plen;
+ l += rlen - plen;
}
}
}
@@ -4545,8 +4530,8 @@ struct expr_replaced : expr_to_std_string> {
return l;
}
constexpr K* place(K* ptr) const noexcept {
- size_t plen = pattern.length();
- if (plen == replLen) {
+ size_t plen = pattern.length(), rlen = repl.length();
+ if (plen == rlen) {
const K* from = what.symbols();
for (size_t start = 0; start < what.length();) {
size_t next = what.find(pattern, start);
@@ -4556,17 +4541,8 @@ struct expr_replaced : expr_to_std_string> {
size_t delta = next - start;
ch_traits::copy(ptr, from + start, delta);
ptr += delta;
- if constexpr (std::is_same_v) {
- ch_traits::copy(ptr, replStart, replLen);
- } else {
- if (!replStart) {
- replStart = ptr;
- expr.place(replStart);
- } else {
- ch_traits::copy(ptr, replStart, replLen);
- }
- }
- ptr += replLen;
+ ch_traits::copy(ptr, repl.symbols(), rlen);
+ ptr += rlen;
start = next + plen;
}
return ptr;
@@ -4581,21 +4557,12 @@ struct expr_replaced : expr_to_std_string> {
for (size_t start = 0, offset = matches_.positions_[0], idx = 1; ;) {
ch_traits::copy(ptr, from + start, offset - start);
ptr += offset - start;
- if constexpr (std::is_same_v) {
- ch_traits::copy(ptr, replStart, replLen);
- } else {
- if (!replStart) {
- replStart = ptr;
- expr.place(replStart);
- } else {
- ch_traits::copy(ptr, replStart, replLen);
- }
- }
- ptr += replLen;
+ ch_traits::copy(ptr, repl.symbols(), rlen);
+ ptr += rlen;
start = offset + plen;
if (start >= last_) {
- size_t tail = what.length() - last_;
- ch_traits::copy(ptr, from + last_, tail);
+ size_t tail = what.length() - start;
+ ch_traits::copy(ptr, from + start, tail);
ptr += tail;
break;
} else {
@@ -4606,6 +4573,130 @@ struct expr_replaced : expr_to_std_string> {
}
};
+/*!
+ * @ingroup StrExprs
+ * @ru @brief Строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки на строковое выражение.
+ * @tparam K - тип строки.
+ * @details Если искомая подстрока не найдена, то строковое выражение даже не вычисляется.
+ * Затем при осуществлении замены строковое выражение вычисляется только один раз в место первой замены,
+ * а в следующие места замен просто копируется символы из первого места. Это позволяет экономить память
+ * и время, если вам надо сделать замену на какую-либо "сборную" строку.
+ * @en @brief A string expression that generates a string replacing all occurrences of the given substring to string expression.
+ * @tparam K - string type.
+ * @details If the search substring is not found, the string expression is not even evaluated.
+ * Then, when performing a replacement, the string expression is evaluated only once at the first replacement location,
+ * and characters from the first location are simply copied to subsequent replacement locations. This saves memory
+ * and time if you need to replace with some kind of "composite" string.
+ */
+template E>
+struct expr_replaced_e : expr_to_std_string> {
+ using symb_type = K;
+ using my_type = expr_replaced;
+ str_src what;
+ const str_src pattern;
+ mutable size_t replLen;
+ mutable find_all_container matches_;
+ mutable size_t last_;
+ const E& expr;
+ /*!
+ * @ru @brief Конструктор.
+ * @param w - исходная строка.
+ * @param p - искомая подстрока.
+ * @param e - строковое выражение для замены.
+ * @en @brief Constructor.
+ * @param w - source string.
+ * @param p - the searched substring.
+ * @param e - string expression to replace.
+ */
+ constexpr expr_replaced_e(str_src w, str_src p, const E& e) : what(w), pattern(p), expr(e) {}
+
+ constexpr size_t length() const {
+ size_t l = what.length(), plen = pattern.length();
+ if (!plen) {
+ return l;
+ }
+ matches_.positions_[0] = what.find(pattern);
+ if (matches_.positions_[0] == -1) {
+ // Не нашли вхождений, нечего менять
+ return l;
+ }
+ matches_.added_ = 1;
+ // Вхождение есть, надо теперь получить длину замены
+ replLen = expr.length();
+ if (replLen == plen) {
+ // Замена той же длины, общая длина не изменится
+ return l;
+ }
+ what.find_all_to(matches_, pattern.symbols(), plen, matches_.positions_[0] + plen, FIND_CACHE_SIZE - 1);
+
+ last_ = matches_.positions_[matches_.added_ - 1] + plen;
+ l += int(replLen - plen) * matches_.added_;
+
+ if (matches_.added_ == FIND_CACHE_SIZE) {
+ for (;;) {
+ size_t next = what.find(pattern.symbols(), plen, last_);
+ if (next == str::npos) {
+ break;
+ }
+ last_ = next + plen;
+ l += replLen - plen;
+ }
+ }
+ if (!l) {
+ matches_.added_ = -1;
+ }
+ return l;
+ }
+ constexpr K* place(K* ptr) const noexcept {
+ if (matches_.added_ == 0) {
+ // не было найдено вхождений
+ return what.place(ptr);
+ } else if (matches_.added_ == -1) {
+ // Строка стала пустой
+ return ptr;
+ }
+ size_t plen = pattern.length();
+ const K* from = what.symbols();
+ ch_traits::copy(ptr, from, matches_.positions_[0]);
+ ptr += matches_.positions_[0];
+ const K* repl = ptr;
+ expr.place((typename E::symb_type*)ptr);
+ ptr += replLen;
+ size_t start = matches_.positions_[0] + plen;
+
+ if (plen == replLen) {
+ for (;;) {
+ size_t next = what.find(pattern, start);
+ if (next == str::npos) {
+ break;
+ }
+ size_t delta = next - start;
+ ch_traits::copy(ptr, from + start, delta);
+ ptr += delta;
+ ch_traits::copy(ptr, repl, replLen);
+ ptr += replLen;
+ start = next + plen;
+ }
+ } else {
+ for (size_t idx = 1;;) {
+ if (start >= last_) {
+ break;
+ }
+ size_t next = idx < FIND_CACHE_SIZE ? matches_.positions_[idx++] : what.find(pattern, start);
+ size_t delta = next - start;
+ ch_traits::copy(ptr, from + start, delta);
+ ptr += delta;
+ ch_traits::copy(ptr, repl, replLen);
+ ptr += replLen;
+ start = next + plen;
+ }
+ }
+ size_t tail = what.length() - start;
+ ch_traits::copy(ptr, from + start, tail);
+ return ptr + tail;
+ }
+};
+
/*!
* @ingroup StrExprs
* @ru @brief Получить строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки.
@@ -4624,7 +4715,7 @@ template, typename T, typename X>
constexpr auto e_repl(A&& w, T&& p, X&& r) {
str_src pattern{std::forward(p)};
str_src repl{std::forward(r)};
- return expr_replaced{get_str_src_from(std::forward(w)), pattern, repl.str, repl.len, 0};
+ return expr_replaced{get_str_src_from(std::forward(w)), pattern, repl};
}
/*!
@@ -4644,7 +4735,7 @@ template, typename T, StrExprForType E
requires std::is_constructible_v, T>
constexpr auto e_repl(A&& w, T&& p, const E& expr) {
str_src pattern{std::forward(p)};
- return expr_replaced{get_str_src_from(std::forward(w)), pattern, nullptr, 0, expr};
+ return expr_replaced_e{get_str_src_from(std::forward(w)), pattern, expr};
}
template
diff --git a/readme.md b/readme.md
index 9ec19ed..619798b 100644
--- a/readme.md
+++ b/readme.md
@@ -3,7 +3,7 @@
[](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
-Version 1.4.0.
+Version 1.5.0.
On Russian | По-русски
@@ -47,7 +47,7 @@ If you actively used `std::string_view` and understood its advantages and disadv
then the `simstr` approach will also be clear to you.
## Main features of the library
-When using only `#include "simstr\strexpr.h"`:
+When using only `#include "simstr/strexpr.h"`:
- Support for working with strings `char`, `char8_t`, `char16_t`, `char32_t`, `wchar_t`.
- Powerful and extensible *"String Expressions"* system.
Allows you to efficiently implement the conversion and addition (concatenation) of strings, string literals, numbers (and possibly other objects),
@@ -65,6 +65,11 @@ When using only `#include "simstr\strexpr.h"`:
- Merging (join) containers of strings into a single string, with specifying delimiters and options - "skip empty", "delimiter after last".
- Splitting strings into parts by a specified delimiter. Splitting is possible immediately into a container with strings, or by calling a functor for
each substring, or by iterating using the `Splitter` iterator.
+- Functions for modifying standard strings with string expressions:
+ - str::append, str::prepend, str::insert, str::change - modify str::string with string expressions,
+ for example, `str::append(text, "count = "_ss + count + " times")`.
+ - str::replace - replaces occurrences of the searched substring with the replacement string or string expression.
+ If the substring is not found, the string expression is not even evaluated.
- Parsing integers with the possibility of "fine" tuning at compile time - you can set options for checking overflow,
skipping whitespace characters, a specific base or auto-selection by prefixes `0x`, `0`, `0b`, `0o`,
admissibility of the `+` sign. Parsing is implemented for all types of strings and characters.
@@ -277,9 +282,9 @@ When connecting only `strexpr.h` - the types `simple_str` and `simple_str_nt<
- [Description of the "Expression Templates" technique used](https://habr.com/ru/articles/936468/) (On Russian)
## Usage
-The library can be used partially, just by taking the file `"include\simstr\strexpr.h"` and including it in your sources
+The library can be used partially, just by taking the file `"include/simstr/strexpr.h"` and including it in your sources
```cpp
-#include "include\simstr\strexpr.h"
+#include "include/simstr/strexpr.h"
```
This will only connect string expressions and simplified implementations of `simple_str` and `simple_str_nt`, without UTF and Unicode functions.
@@ -297,8 +302,8 @@ function(add_simstr)
simstr
GIT_REPOSITORY https://github.com/orefkov/simstr.git
GIT_SHALLOW TRUE
- GIT_TAG tags/rel1.4.0 # Укажите нужный релиз
- FIND_PACKAGE_ARGS NAMES simstr 1.4.0
+ GIT_TAG tags/rel1.5.0 # Укажите нужный релиз
+ FIND_PACKAGE_ARGS NAMES simstr 1.5.0
)
FetchContent_MakeAvailable(simstr)
endfunction()
diff --git a/readme_ru.md b/readme_ru.md
index 1acf215..51f19b6 100644
--- a/readme_ru.md
+++ b/readme_ru.md
@@ -3,7 +3,7 @@
[](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
-Версия 1.4.0.
+Версия 1.5.0.
On English | По-английски
@@ -48,7 +48,7 @@
то подход `simstr` вам также будет понятен.
## Основные возможности библиотеки
-При использовании только `#include "simstr\strexpr.h"`:
+При использовании только `#include "simstr/strexpr.h"`:
- Поддержка работы со строками `char`, `char8_t`, `char16_t`, `char32_t`, `wchar_t`.
- Мощная и расширяемая система *"Строковых выражений"*.
Позволяет эффективно реализовать преобразование и сложение (конкатенацию) строк, строковых литералов, чисел (и возможно других объектов),
@@ -66,6 +66,11 @@
- Слияние (join) контейнеров строк в единую строку, с заданием разделителей и опций - "пропускать пустые", "разделитель после последней".
- Разбиение (split) строк на части по заданному разделителю. Разбиение возможно сразу в контейнер со строками, либо вызовом функтора для
каждой подстроки, либо путем итерации с помощью итератора `Splitter`.
+- Функции модификации стандартных строк строковыми выражениями:
+ - str::append, str::prepend, str::insert, str::change - меняют str::string строковыми выражениями,
+ например `str::append(text, "count = "_ss + count)`.
+ - str::replace - заменяет вхождения искомой подстроки на строку замены или строковое выражение.
+ Если подстрока не найдена, строковое выражение даже не вычисляется.
- Парсинг целых чисел с возможностью "тонкой" настройки при компиляции - можно задавать опции проверки переполнения,
пропуск пробельных символов, конкретное основание счисления либо автовыбор по префиксам `0x`, `0`, `0b`, `0o`,
допустимость знака `+`. Парсинг реализован для всех видов строк и символов.
@@ -278,9 +283,9 @@ int split_and_calc_total_sim(ssa numbers, ssa delimiter) {
- [Описание применяемой техники "Expression Templates"](https://habr.com/ru/articles/936468/)
## Использование
-Библиотеку можно использовать частично, просто взяв файл `"include\simstr\strexpr.h"` и включив в свои исходники
+Библиотеку можно использовать частично, просто взяв файл `"include/simstr/strexpr.h"` и включив в свои исходники
```cpp
-#include "include\simstr\strexpr.h"
+#include "include/simstr/strexpr.h"
```
Это подключит только строковые выражения и упрощённые реализации `simple_str` и `simple_str_nt`, без функций работы с UTF и Unicode.
@@ -298,8 +303,8 @@ function(add_simstr)
simstr
GIT_REPOSITORY https://github.com/orefkov/simstr.git
GIT_SHALLOW TRUE
- GIT_TAG tags/rel1.4.0 # Укажите нужный релиз
- FIND_PACKAGE_ARGS NAMES simstr 1.4.0
+ GIT_TAG tags/rel1.5.0 # Укажите нужный релиз
+ FIND_PACKAGE_ARGS NAMES simstr 1.5.0
)
FetchContent_MakeAvailable(simstr)
endfunction()
diff --git a/src/sstring.cpp b/src/sstring.cpp
index 52d4b7c..a8a644c 100644
--- a/src/sstring.cpp
+++ b/src/sstring.cpp
@@ -1,7 +1,9 @@
/*
+ * ver. 1.5.0
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
- * ver. 1.0
* Реализация строковых функций
+ * (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
+ * Implementation of string functions
*/
#include "simstr/simple_unicode.h"
#include "simstr/sstring.h"
@@ -1466,6 +1468,5 @@ SIMSTR_API std::optional impl_to_double(const K* start, const K* end) {
template SIMSTR_API std::optional impl_to_double(const u8s* start, const u8s* end);
template SIMSTR_API std::optional impl_to_double(const u16s* start, const u16s* end);
template SIMSTR_API std::optional impl_to_double(const u32s* start, const u32s* end);
-template SIMSTR_API std::optional impl_to_double(const uws* start, const uws* end);
} // namespace simstr
diff --git a/tests/test_expr_only.cpp b/tests/test_expr_only.cpp
index c0b3369..4051770 100644
--- a/tests/test_expr_only.cpp
+++ b/tests/test_expr_only.cpp
@@ -1,4 +1,12 @@
-#include "../include/simstr/strexpr.h"
+/*
+ * ver. 1.5.0
+ * (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
+ * Тесты simstr
+ * (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
+ * Test of simstr
+ */
+
+#include "../include/simstr/strexpr.h"
#include
#include
@@ -284,6 +292,14 @@ TEST(StrExpr, StrReplace) {
std::u16string src = u"-aaaaaaaaaaaaaaaa--";
EXPECT_EQ(str::replace(src, u"a", u"vv"_ss + 10, 5, 3), u"-aaaavv10vv10vv10aaaaaaaaa--");
}
+ {
+ std::u32string a = U"<" + e_repl(U"test"sv, U"t", U"a" + e_repl(U"test"s, U"es", U"se")) + U">";
+ EXPECT_EQ(a, U"");
+ }
+ {
+ std::string a = u8"<" + e_repl("test"sv, "t", u8"a" + e_repl("test"s, "es", "se")) + ">";
+ EXPECT_EQ(a, "");
+ }
}
} // namespace simstr::tests
diff --git a/tests/test_str.cpp b/tests/test_str.cpp
index 8133f5b..ba87b8e 100644
--- a/tests/test_str.cpp
+++ b/tests/test_str.cpp
@@ -1,4 +1,12 @@
-#include
+/*
+ * ver. 1.5.0
+ * (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
+ * Тесты simstr
+ * (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
+ * Test of simstr
+ */
+
+#include
#include
using namespace std::literals;
@@ -1918,6 +1926,27 @@ TEST(SimStr, StrRepl) {
a = e_repl("test"_ss, "t", "a"_ss + "1" + 10);
EXPECT_EQ(a, "a110esa110");
+
+ a = e_repl("test"_ss, "x", "a"_ss + "1" + 10);
+ EXPECT_EQ(a, "test");
+
+ a = e_repl("test"_ss, "t", eea + "a");
+ EXPECT_EQ(a, "aesa");
+
+ a = e_repl("tesd"_ss, "t", eea + "a");
+ EXPECT_EQ(a, "aesd");
+
+ a = e_repl("tttt"_ss, "t", eea);
+ EXPECT_EQ(a, "");
+
+ a = e_repl("-tttttttttttttttttt-"_ss, "t", eea + "a");
+ EXPECT_EQ(a, "-aaaaaaaaaaaaaaaaaa-");
+
+ a = e_repl("-tttttttttttttttttt-"_ss, "t", eea + "aa");
+ EXPECT_EQ(a, "-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-");
+
+ a = "<" + e_repl("test"sv, "t", "a" + e_repl("test"s, "es", "se")) + ">";
+ EXPECT_EQ(a, "");
}
TEST(SimStr, HexEpr) {