This commit is contained in:
Aleksandr Orefkov 2026-01-25 13:39:22 +03:00
parent 620383a5a4
commit 35d2ea2ee8
11 changed files with 232 additions and 79 deletions

View File

@ -5,7 +5,7 @@ include(FetchContent)
project( project(
simstr simstr
VERSION 1.4.0 VERSION 1.5.0
DESCRIPTION "Yet another modern C++ string library" DESCRIPTION "Yet another modern C++ string library"
HOMEPAGE_URL "https://github.com/orefkov/simstr" HOMEPAGE_URL "https://github.com/orefkov/simstr"
LANGUAGES CXX LANGUAGES CXX
@ -116,7 +116,7 @@ if(SIMSTR_BUILD_TESTS)
googletest googletest
# Specify the commit you depend on and update it regularly. # Specify the commit you depend on and update it regularly.
URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.zip 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 # For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt FALSE CACHE BOOL "" FORCE) set(gtest_force_shared_crt FALSE CACHE BOOL "" FORCE)
@ -134,7 +134,7 @@ function(GBencmark)
googlebench googlebench
# Specify the commit you depend on and update it regularly. # Specify the commit you depend on and update it regularly.
URL https://github.com/google/benchmark/archive/refs/tags/v1.9.4.zip 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_TESTING OFF)
set(BENCHMARK_ENABLE_LTO OFF) set(BENCHMARK_ENABLE_LTO OFF)

View File

@ -48,7 +48,7 @@ PROJECT_NAME = "simstr"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # 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 # 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 # for a project that appears at the top of each page and should give viewers a

View File

@ -48,7 +48,7 @@ PROJECT_NAME = "simstr"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # 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 # 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 # for a project that appears at the top of each page and should give viewers a

View File

@ -1,6 +1,6 @@
/* /*
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com * (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
* ver. 1.0 * ver. 1.5.0
*/ */
#pragma once #pragma once

View File

@ -1,9 +1,9 @@
/* /*
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com * (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
* ver. 1.4.0 * ver. 1.5.0
* Классы для работы со строками * Классы для работы со строками
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com * (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
* ver. 1.4.0 * ver. 1.5.0
* Classes for working with strings * Classes for working with strings
*/ */
@ -314,7 +314,13 @@ public:
return {}; return {};
} }
#endif #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. * @ru @brief Преобразовать строку в double.

View File

@ -1,5 +1,5 @@
/* /*
* ver. 1.4.0 * ver. 1.5.0
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com * (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
* База для строковых конкатенаций через выражения времени компиляции * База для строковых конкатенаций через выражения времени компиляции
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com * (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
@ -3282,7 +3282,7 @@ public:
return {}; return {};
} }
double d{}; 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 d;
} }
return {}; return {};
@ -4477,32 +4477,20 @@ constexpr auto e_repl(A&& w, T&& p, X&& r) {
/*! /*!
* @ingroup StrExprs * @ingroup StrExprs
* @ru @brief Строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки. * @ru @brief Строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки на другую строку.
* @tparam K - тип строки. * @tparam K - тип строки.
* @details `e_repl` позволяет заменять только с использование строковых литералов. * @en @brief A string expression that generates a string replacing all occurrences of the given substring to another string.
* В случае, когда искомая подстрока или строка замены не известны при компиляции, и задаются в runtime,
* следует использовать этот тип, например:
* @en @brief A string expression that generates a string replacing all occurrences of the given substring.
* @tparam K - string type. * @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 = "<header>" + expr_replaced<u8s>{source, pattern, repl} + "</header>";
* ```
*/ */
template<typename K, typename E = int> template<typename K>
struct expr_replaced : expr_to_std_string<expr_replaced<K>> { struct expr_replaced : expr_to_std_string<expr_replaced<K>> {
using symb_type = K; using symb_type = K;
using my_type = expr_replaced<K>; using my_type = expr_replaced<K>;
str_src<K> what; str_src<K> what;
const str_src<K> pattern; const str_src<K> pattern;
mutable K* replStart; const str_src<K> repl;
mutable size_t replLen;
mutable find_all_container<FIND_CACHE_SIZE> matches_; mutable find_all_container<FIND_CACHE_SIZE> matches_;
mutable size_t last_; mutable size_t last_;
const E& expr;
/*! /*!
* @ru @brief Конструктор. * @ru @brief Конструктор.
* @param w - исходная строка. * @param w - исходная строка.
@ -4513,20 +4501,17 @@ struct expr_replaced : expr_to_std_string<expr_replaced<K>> {
* @param p - the searched substring. * @param p - the searched substring.
* @param r - replacement string. * @param r - replacement string.
*/ */
constexpr expr_replaced(str_src<K> w, str_src<K> p, const K* r, size_t rl, const E& e) : what(w), pattern(p), replStart(const_cast<K*>(r)), replLen(rl), expr(e) {} constexpr expr_replaced(str_src<K> w, str_src<K> p, str_src<K> r) : what(w), pattern(p), repl(r) {}
constexpr size_t length() const { constexpr size_t length() const {
size_t l = what.length(), plen = pattern.length(); size_t l = what.length(), plen = pattern.length(), rlen = repl.length();
if constexpr (!std::is_same_v<E, int>) { if (!plen || plen == rlen) {
replLen = expr.length();
}
if (!plen || plen == replLen) {
return l; return l;
} }
what.find_all_to(matches_, pattern.symbols(), plen, 0, FIND_CACHE_SIZE); what.find_all_to(matches_, pattern.symbols(), plen, 0, FIND_CACHE_SIZE);
if (matches_.added_) { if (matches_.added_) {
last_ = matches_.positions_[matches_.added_ - 1] + plen; 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) { if (matches_.added_ == FIND_CACHE_SIZE) {
for (;;) { for (;;) {
@ -4535,7 +4520,7 @@ struct expr_replaced : expr_to_std_string<expr_replaced<K>> {
break; break;
} }
last_ = next + plen; last_ = next + plen;
l += replLen - plen; l += rlen - plen;
} }
} }
} }
@ -4545,8 +4530,8 @@ struct expr_replaced : expr_to_std_string<expr_replaced<K>> {
return l; return l;
} }
constexpr K* place(K* ptr) const noexcept { constexpr K* place(K* ptr) const noexcept {
size_t plen = pattern.length(); size_t plen = pattern.length(), rlen = repl.length();
if (plen == replLen) { if (plen == rlen) {
const K* from = what.symbols(); const K* from = what.symbols();
for (size_t start = 0; start < what.length();) { for (size_t start = 0; start < what.length();) {
size_t next = what.find(pattern, start); size_t next = what.find(pattern, start);
@ -4556,17 +4541,8 @@ struct expr_replaced : expr_to_std_string<expr_replaced<K>> {
size_t delta = next - start; size_t delta = next - start;
ch_traits<K>::copy(ptr, from + start, delta); ch_traits<K>::copy(ptr, from + start, delta);
ptr += delta; ptr += delta;
if constexpr (std::is_same_v<E, int>) { ch_traits<K>::copy(ptr, repl.symbols(), rlen);
ch_traits<K>::copy(ptr, replStart, replLen); ptr += rlen;
} else {
if (!replStart) {
replStart = ptr;
expr.place(replStart);
} else {
ch_traits<K>::copy(ptr, replStart, replLen);
}
}
ptr += replLen;
start = next + plen; start = next + plen;
} }
return ptr; return ptr;
@ -4581,21 +4557,12 @@ struct expr_replaced : expr_to_std_string<expr_replaced<K>> {
for (size_t start = 0, offset = matches_.positions_[0], idx = 1; ;) { for (size_t start = 0, offset = matches_.positions_[0], idx = 1; ;) {
ch_traits<K>::copy(ptr, from + start, offset - start); ch_traits<K>::copy(ptr, from + start, offset - start);
ptr += offset - start; ptr += offset - start;
if constexpr (std::is_same_v<E, int>) { ch_traits<K>::copy(ptr, repl.symbols(), rlen);
ch_traits<K>::copy(ptr, replStart, replLen); ptr += rlen;
} else {
if (!replStart) {
replStart = ptr;
expr.place(replStart);
} else {
ch_traits<K>::copy(ptr, replStart, replLen);
}
}
ptr += replLen;
start = offset + plen; start = offset + plen;
if (start >= last_) { if (start >= last_) {
size_t tail = what.length() - last_; size_t tail = what.length() - start;
ch_traits<K>::copy(ptr, from + last_, tail); ch_traits<K>::copy(ptr, from + start, tail);
ptr += tail; ptr += tail;
break; break;
} else { } else {
@ -4606,6 +4573,130 @@ struct expr_replaced : expr_to_std_string<expr_replaced<K>> {
} }
}; };
/*!
* @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<typename K, StrExprForType<K> E>
struct expr_replaced_e : expr_to_std_string<expr_replaced_e<K, E>> {
using symb_type = K;
using my_type = expr_replaced<K>;
str_src<K> what;
const str_src<K> pattern;
mutable size_t replLen;
mutable find_all_container<FIND_CACHE_SIZE> 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<K> w, str_src<K> 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<K>::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<K>::copy(ptr, from + start, delta);
ptr += delta;
ch_traits<K>::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<K>::copy(ptr, from + start, delta);
ptr += delta;
ch_traits<K>::copy(ptr, repl, replLen);
ptr += replLen;
start = next + plen;
}
}
size_t tail = what.length() - start;
ch_traits<K>::copy(ptr, from + start, tail);
return ptr + tail;
}
};
/*! /*!
* @ingroup StrExprs * @ingroup StrExprs
* @ru @brief Получить строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки. * @ru @brief Получить строковое выражение, генерирующее строку с заменой всех вхождений заданной подстроки.
@ -4624,7 +4715,7 @@ template<StrSource A, typename K = src_str_t<A>, typename T, typename X>
constexpr auto e_repl(A&& w, T&& p, X&& r) { constexpr auto e_repl(A&& w, T&& p, X&& r) {
str_src<K> pattern{std::forward<T>(p)}; str_src<K> pattern{std::forward<T>(p)};
str_src<K> repl{std::forward<X>(r)}; str_src<K> repl{std::forward<X>(r)};
return expr_replaced<K, int>{get_str_src_from(std::forward<A>(w)), pattern, repl.str, repl.len, 0}; return expr_replaced<K>{get_str_src_from(std::forward<A>(w)), pattern, repl};
} }
/*! /*!
@ -4644,7 +4735,7 @@ template<StrSource A, typename K = src_str_t<A>, typename T, StrExprForType<K> E
requires std::is_constructible_v<str_src<K>, T> requires std::is_constructible_v<str_src<K>, T>
constexpr auto e_repl(A&& w, T&& p, const E& expr) { constexpr auto e_repl(A&& w, T&& p, const E& expr) {
str_src<K> pattern{std::forward<T>(p)}; str_src<K> pattern{std::forward<T>(p)};
return expr_replaced<K, E>{get_str_src_from(std::forward<A>(w)), pattern, nullptr, 0, expr}; return expr_replaced_e<K, E>{get_str_src_from(std::forward<A>(w)), pattern, expr};
} }
template<bool UseVectorForReplace> template<bool UseVectorForReplace>

View File

@ -3,7 +3,7 @@
[![CMake on multiple platforms](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml) [![CMake on multiple platforms](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
Version 1.4.0. Version 1.5.0.
<span class="obfuscator"><a href="readme_ru.md">On Russian | По-русски</a></span> <span class="obfuscator"><a href="readme_ru.md">On Russian | По-русски</a></span>
@ -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. then the `simstr` approach will also be clear to you.
## Main features of the library ## 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`. - Support for working with strings `char`, `char8_t`, `char16_t`, `char32_t`, `wchar_t`.
- Powerful and extensible *"String Expressions"* system. - 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), 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". - 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 - 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. 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, - 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`, 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. 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<K>` and `simple_str_nt<
- [Description of the "Expression Templates" technique used](https://habr.com/ru/articles/936468/) (On Russian) - [Description of the "Expression Templates" technique used](https://habr.com/ru/articles/936468/) (On Russian)
## Usage ## 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 ```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. 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 simstr
GIT_REPOSITORY https://github.com/orefkov/simstr.git GIT_REPOSITORY https://github.com/orefkov/simstr.git
GIT_SHALLOW TRUE GIT_SHALLOW TRUE
GIT_TAG tags/rel1.4.0 # Укажите нужный релиз GIT_TAG tags/rel1.5.0 # Укажите нужный релиз
FIND_PACKAGE_ARGS NAMES simstr 1.4.0 FIND_PACKAGE_ARGS NAMES simstr 1.5.0
) )
FetchContent_MakeAvailable(simstr) FetchContent_MakeAvailable(simstr)
endfunction() endfunction()

View File

@ -3,7 +3,7 @@
[![CMake on multiple platforms](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml) [![CMake on multiple platforms](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
Версия 1.4.0. Версия 1.5.0.
<span class="obfuscator"><a href="readme.md">On English | По-английски</a></span> <span class="obfuscator"><a href="readme.md">On English | По-английски</a></span>
@ -48,7 +48,7 @@
то подход `simstr` вам также будет понятен. то подход `simstr` вам также будет понятен.
## Основные возможности библиотеки ## Основные возможности библиотеки
При использовании только `#include "simstr\strexpr.h"`: При использовании только `#include "simstr/strexpr.h"`:
- Поддержка работы со строками `char`, `char8_t`, `char16_t`, `char32_t`, `wchar_t`. - Поддержка работы со строками `char`, `char8_t`, `char16_t`, `char32_t`, `wchar_t`.
- Мощная и расширяемая система *"Строковых выражений"*. - Мощная и расширяемая система *"Строковых выражений"*.
Позволяет эффективно реализовать преобразование и сложение (конкатенацию) строк, строковых литералов, чисел (и возможно других объектов), Позволяет эффективно реализовать преобразование и сложение (конкатенацию) строк, строковых литералов, чисел (и возможно других объектов),
@ -66,6 +66,11 @@
- Слияние (join) контейнеров строк в единую строку, с заданием разделителей и опций - "пропускать пустые", "разделитель после последней". - Слияние (join) контейнеров строк в единую строку, с заданием разделителей и опций - "пропускать пустые", "разделитель после последней".
- Разбиение (split) строк на части по заданному разделителю. Разбиение возможно сразу в контейнер со строками, либо вызовом функтора для - Разбиение (split) строк на части по заданному разделителю. Разбиение возможно сразу в контейнер со строками, либо вызовом функтора для
каждой подстроки, либо путем итерации с помощью итератора `Splitter`. каждой подстроки, либо путем итерации с помощью итератора `Splitter`.
- Функции модификации стандартных строк строковыми выражениями:
- str::append, str::prepend, str::insert, str::change - меняют str::string строковыми выражениями,
например `str::append(text, "count = "_ss + count)`.
- str::replace - заменяет вхождения искомой подстроки на строку замены или строковое выражение.
Если подстрока не найдена, строковое выражение даже не вычисляется.
- Парсинг целых чисел с возможностью "тонкой" настройки при компиляции - можно задавать опции проверки переполнения, - Парсинг целых чисел с возможностью "тонкой" настройки при компиляции - можно задавать опции проверки переполнения,
пропуск пробельных символов, конкретное основание счисления либо автовыбор по префиксам `0x`, `0`, `0b`, `0o`, пропуск пробельных символов, конкретное основание счисления либо автовыбор по префиксам `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/) - [Описание применяемой техники "Expression Templates"](https://habr.com/ru/articles/936468/)
## Использование ## Использование
Библиотеку можно использовать частично, просто взяв файл `"include\simstr\strexpr.h"` и включив в свои исходники Библиотеку можно использовать частично, просто взяв файл `"include/simstr/strexpr.h"` и включив в свои исходники
```cpp ```cpp
#include "include\simstr\strexpr.h" #include "include/simstr/strexpr.h"
``` ```
Это подключит только строковые выражения и упрощённые реализации `simple_str` и `simple_str_nt`, без функций работы с UTF и Unicode. Это подключит только строковые выражения и упрощённые реализации `simple_str` и `simple_str_nt`, без функций работы с UTF и Unicode.
@ -298,8 +303,8 @@ function(add_simstr)
simstr simstr
GIT_REPOSITORY https://github.com/orefkov/simstr.git GIT_REPOSITORY https://github.com/orefkov/simstr.git
GIT_SHALLOW TRUE GIT_SHALLOW TRUE
GIT_TAG tags/rel1.4.0 # Укажите нужный релиз GIT_TAG tags/rel1.5.0 # Укажите нужный релиз
FIND_PACKAGE_ARGS NAMES simstr 1.4.0 FIND_PACKAGE_ARGS NAMES simstr 1.5.0
) )
FetchContent_MakeAvailable(simstr) FetchContent_MakeAvailable(simstr)
endfunction() endfunction()

View File

@ -1,7 +1,9 @@
/* /*
* ver. 1.5.0
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com * (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/simple_unicode.h"
#include "simstr/sstring.h" #include "simstr/sstring.h"
@ -1466,6 +1468,5 @@ SIMSTR_API std::optional<double> impl_to_double(const K* start, const K* end) {
template SIMSTR_API std::optional<double> impl_to_double<u8s>(const u8s* start, const u8s* end); template SIMSTR_API std::optional<double> impl_to_double<u8s>(const u8s* start, const u8s* end);
template SIMSTR_API std::optional<double> impl_to_double<u16s>(const u16s* start, const u16s* end); template SIMSTR_API std::optional<double> impl_to_double<u16s>(const u16s* start, const u16s* end);
template SIMSTR_API std::optional<double> impl_to_double<u32s>(const u32s* start, const u32s* end); template SIMSTR_API std::optional<double> impl_to_double<u32s>(const u32s* start, const u32s* end);
template SIMSTR_API std::optional<double> impl_to_double<uws>(const uws* start, const uws* end);
} // namespace simstr } // namespace simstr

View File

@ -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 <gtest/gtest.h> #include <gtest/gtest.h>
#include <list> #include <list>
@ -284,6 +292,14 @@ TEST(StrExpr, StrReplace) {
std::u16string src = u"-aaaaaaaaaaaaaaaa--"; std::u16string src = u"-aaaaaaaaaaaaaaaa--";
EXPECT_EQ(str::replace(src, u"a", u"vv"_ss + 10, 5, 3), u"-aaaavv10vv10vv10aaaaaaaaa--"); 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"<atsetesatset>");
}
{
std::string a = u8"<" + e_repl("test"sv, "t", u8"a" + e_repl("test"s, "es", "se")) + ">";
EXPECT_EQ(a, "<atsetesatset>");
}
} }
} // namespace simstr::tests } // namespace simstr::tests

View File

@ -1,4 +1,12 @@
#include <simstr/sstring.h> /*
* ver. 1.5.0
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
* Тесты simstr
* (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com
* Test of simstr
*/
#include <simstr/sstring.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
using namespace std::literals; using namespace std::literals;
@ -1918,6 +1926,27 @@ TEST(SimStr, StrRepl) {
a = e_repl("test"_ss, "t", "a"_ss + "1" + 10); a = e_repl("test"_ss, "t", "a"_ss + "1" + 10);
EXPECT_EQ(a, "a110esa110"); 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, "<atsetesatset>");
} }
TEST(SimStr, HexEpr) { TEST(SimStr, HexEpr) {