simrex 1.0
Simstr wrapper for Oniguruma regexp
 
Загрузка...
Поиск...
Не найдено
onig.h
1/*
2* (c) Проект "SimRex", Александр Орефков orefkov@gmail.com
3* Регэкспы на oniguruma для SimStr.
4*/
5#pragma once
6#include <simstr/sstring.h>
7#include <oniguruma.h>
8//#include <onigposix.h>
9//#include <oniggnu.h>
10
11#ifdef SIMREX_IN_SHARED
12 #if defined(_MSC_VER) || (defined(__clang__) && __has_declspec_attribute(dllexport))
13 #ifdef SIMREX_EXPORT
14 #define SIMREX_API __declspec(dllexport)
15 #else
16 #define SIMREX_API __declspec(dllimport)
17 #endif
18 #elif (defined(__GNUC__) || defined(__GNUG__)) && defined(SIMSTR_EXPORT)
19 #define SIMREX_API __attribute__((visibility("default")))
20 #else
21 #define SIMREX_API
22 #endif
23#else
24 #define SIMREX_API
25#endif
26
27namespace simrex {
28using namespace simstr;
29using namespace simstr::literals;
30
31namespace utils {
32
33template<auto delete_>
34struct SimpleDeleter {
35 void operator()(auto ptr) const {
36 if (ptr) {
37 delete_(ptr);
38 }
39 }
40};
41
42} // namespace utils
43
44struct OnigRegionDeleter {
45 void operator()(OnigRegion* region) const {
46 onig_region_free(region, 1);
47 }
48};
49
50using RegexPtr = std::unique_ptr<OnigRegexType, utils::SimpleDeleter<onig_free>>;
51using RegionPtr = std::unique_ptr<OnigRegion, OnigRegionDeleter>;
52
53class OnigRegExpBase {
54public:
55 OnigRegExpBase(const OnigRegExpBase&) = delete;
56 OnigRegExpBase& operator=(const OnigRegExpBase&) = delete;
57
58 operator OnigRegex() const {
59 return regexp_.get();
60 }
61
62 bool isValid() const {
63 return (bool)regexp_;
64 }
65
66protected:
67 OnigRegExpBase() = default;
68 OnigRegExpBase(const OnigUChar* pattern, size_t length, OnigEncoding enc) : regexp_{create_regex(pattern, length, enc)} {}
69
70 static OnigRegex create_regex(const OnigUChar* pattern, size_t length, OnigEncoding enc) {
71 const OnigUChar *end = pattern + length;
72 OnigRegex temp = nullptr;
73 return ONIG_NORMAL == onig_new(&temp, pattern, end, ONIG_OPTION_DEFAULT, enc, ONIG_SYNTAX_DEFAULT, nullptr) ? temp : nullptr;
74 }
75
76 OnigRegExpBase(OnigRegExpBase&& other) noexcept = default;
77 ~OnigRegExpBase() = default;
78 OnigRegExpBase& operator=(OnigRegExpBase&& other) noexcept = default;
79
80 int search(const OnigUChar* start, size_t length, size_t offset) const {
81 const OnigUChar* end = start + length;
82 return onig_search(*this, start, end, start + offset, end, nullptr, ONIG_OPTION_NONE);
83 }
84
85 RegexPtr regexp_;
86};
87
88template<typename K>
89OnigEncoding rexEncoding() {
90 if constexpr (sizeof(K) == 2) {
91 return std::endian::native == std::endian::big ? ONIG_ENCODING_UTF16_BE : ONIG_ENCODING_UTF16_LE;
92 }
93 if constexpr (sizeof(K) == 4) {
94 return std::endian::native == std::endian::big ? ONIG_ENCODING_UTF32_BE : ONIG_ENCODING_UTF32_LE;
95 }
96 return ONIG_ENCODING_UTF8;
97}
98
99template<typename K>
100struct RexTraits {
101 static const OnigUChar* toChar(const K* ptr) {
102 return reinterpret_cast<const OnigUChar*>(ptr);
103 }
104 static int toLen(size_t len) {
105 return int(len * sizeof(K));
106 }
107 static const K* fromChar(const OnigUChar* ptr) {
108 return reinterpret_cast<const K*>(ptr);
109 }
110 static size_t fromLen(int len) {
111 return size_t(len / sizeof(K));
112 }
113};
114
119template<typename K>
120class OnigRegexp : public OnigRegExpBase {
121 using rt = RexTraits<K>;
122
123public:
124 using str_type = simple_str<K>;
125
126 OnigRegexp() = default;
127 OnigRegexp(OnigRegexp&& other) noexcept = default;
128 ~OnigRegexp() = default;
129
130 OnigRegexp(const OnigRegexp&) = delete;
131 OnigRegexp& operator=(const OnigRegexp&) = delete;
132
137 OnigRegexp(str_type pattern) : OnigRegExpBase(rt::toChar(pattern.symbols()), rt::toLen(pattern.length()), rexEncoding<K>()) {}
138
139 OnigRegexp& operator=(OnigRegexp&& other) noexcept = default;
140
147 size_t search(str_type text, size_t offset = 0) {
148 int res = OnigRegExpBase::search(rt::toChar(text.symbols()), rt::toLen(text.length()), rt::toLen(offset));
149 return res < 0 ? (size_t)res : rt::fromLen(res);
150 }
151
158 SIMREX_API size_t count_of(const str_type& text, size_t maxCount = -1, size_t offset = 0);
166 template<typename T = str_type>
167 T first_founded(str_type text, size_t offset = 0) const {
168 return first_founded_str(text, offset);
169 }
170
178 template<typename T = str_type>
179 std::vector<T> all_founded(str_type text, size_t offset = 0, size_t maxCount = -1) const {
180 std::vector<T> matches;
181 all_founded_str(text, offset, maxCount, [](str_type word, void* res) {
182 reinterpret_cast<std::vector<T>*>(res)->emplace_back(word);
183 }, &matches);
184 return matches;
185 }
186
194 template<typename T = str_type>
195 std::vector<T> first_matched(str_type text, size_t offset = 0) const {
196 std::vector<T> matches;
197 if (isValid()) {
198 const OnigUChar *start = rt::toChar(text.begin()), *end = rt::toChar(text.end());
199 RegionPtr region{onig_region_new()};
200 if (onig_search(*this, start, end, start + rt::toLen(offset), end, region.get(), ONIG_OPTION_NONE) >= 0) {
201 matches.reserve(region->num_regs);
202 for (int i = 0; i < region->num_regs; i++) {
203 matches.emplace_back(str_type{rt::fromChar(start + region->beg[i]), rt::fromLen(region->end[i] - region->beg[i])});
204 }
205 }
206 }
207 return matches;
208 }
209
218 template<typename T = str_type>
219 std::vector<std::vector<T>> all_matched(str_type text, size_t offset = 0, size_t maxCount = -1) const {
220 std::vector<std::vector<T>> matches;
221 if (isValid()) {
222 const OnigUChar *start = rt::toChar(text.begin()), *end = rt::toChar(text.end()), *at = start + rt::toLen(offset);
223 RegionPtr region{onig_region_new()};
224 for (size_t count = 0; count < maxCount; count++) {
225 if (onig_search(*this, start, end, at, end, region.get(), ONIG_OPTION_NONE) >= 0) {
226 auto& match = matches.emplace_back();
227 match.reserve(region->num_regs);
228 for (int i = 0; i < region->num_regs; i++) {
229 match.emplace_back(str_type{rt::fromChar(start + region->beg[i]), rt::fromLen(region->end[i] - region->beg[i])});
230 }
231 const OnigUChar* newAt = start + region->end[0];
232 if (newAt <= at || newAt >= end) {
233 break;
234 }
235 at = newAt;
236 } else {
237 break;
238 }
239 }
240 }
241 return matches;
242 }
243 // Возвращает массив пар - индекс начала совпадения в строке и его текст + подгруппы
244
254 template<typename T = str_type>
255 std::vector<std::pair<size_t, T>> first_match(str_type text, size_t offset = 0) const {
256 std::vector<std::pair<size_t, T>> matches;
257 if (isValid()) {
258 const OnigUChar *start = rt::toChar(text.begin()), *end = rt::toChar(text.end());
259 RegionPtr region{onig_region_new()};
260 int result = onig_search(*this, start, end, start + rt::toLen(offset), end, region.get(), ONIG_OPTION_NONE);
261 if (result >= 0) {
262 matches.reserve(region->num_regs);
263 for (int i = 0; i < region->num_regs; i++) {
264 matches.emplace_back(
265 rt::fromLen(region->beg[i]),
266 str_type{rt::fromChar(start + region->beg[i]), rt::fromLen(region->end[i] - region->beg[i])});
267 }
268 }
269 }
270 return matches;
271 }
272
283 template<typename T = str_type>
284 std::vector<std::vector<std::pair<size_t, T>>> all_matches(str_type text, size_t offset = 0, size_t maxCount = -1) const {
285 std::vector<std::vector<std::pair<size_t, T>>> matches;
286 if (isValid()) {
287 const OnigUChar *start = rt::toChar(text.begin()), *end = rt::toChar(text.end()), *at = start + rt::toLen(offset);
288 RegionPtr region{onig_region_new()};
289 for (size_t count = 0; count < maxCount; count++) {
290 if (onig_search(*this, start, end, at, end, region.get(), ONIG_OPTION_NONE) >= 0) {
291 auto& match = matches.emplace_back();
292 match.reserve(region->num_regs);
293 for (int i = 0; i < region->num_regs; i++) {
294 match.emplace_back(
295 rt::fromLen(region->beg[i]),
296 str_type{rt::fromChar(start + region->beg[i]), rt::fromLen(region->end[i] - region->beg[i])});
297 }
298 const OnigUChar* newAt = start + region->end[0];
299 if (newAt <= at || newAt >= end) {
300 break;
301 }
302 at = newAt;
303 } else {
304 break;
305 }
306 }
307 }
308 return matches;
309 }
310
328 template<StrType<K> U, typename T = std::remove_cvref_t<U>> requires storable_str<T, K>
329 T replace(U&& text, str_type replText, size_t offset = 0, size_t maxCount = -1, bool substGroups = true) {
330 if (!regexp_) {
331 return text;
332 }
333 auto replaces = parse_replaces(replText, substGroups);
334
335 std::vector<str_type> parts;
336 size_t delta = 0;
337 const OnigUChar *starto = rt::toChar(text.begin()), *end = rt::toChar(text.end()), *at = starto + rt::toLen(offset),
338 *prevStart = starto;
339 RegionPtr region{onig_region_new()};
340 for (size_t count = 0; count < maxCount; count++) {
341 int result = onig_search(*this, starto, end, at, end, region.get(), ONIG_OPTION_NONE);
342 if (result >= 0) {
343 delta = rt::fromLen(int(starto + region->beg[0] - prevStart));
344 if (delta) {
345 parts.emplace_back(rt::fromChar(prevStart), delta);
346 }
347 for (const auto& [idx, text]: replaces) {
348 if (idx < 0) {
349 parts.emplace_back(text);
350 } else if (idx < region->num_regs) {
351 delta = rt::fromLen(region->end[idx] - region->beg[idx]);
352 if (delta) {
353 parts.emplace_back(rt::fromChar(starto + region->beg[idx]), delta);
354 }
355 }
356 }
357 const OnigUChar* newAt = starto + region->end[0];
358 if (newAt <= at || at >= end) {
359 break;
360 }
361 at = prevStart = newAt;
362 } else {
363 break;
364 }
365 }
366 if (parts.empty()) {
367 return std::forward<U>(text);
368 }
369 if (at < end) {
370 parts.emplace_back(rt::fromChar(at), rt::fromLen(int(end - at)));
371 }
372 return expr_join<K, std::vector<str_type>, 0, false, false>{parts, nullptr};
373 }
374
387 template<StrType<K> U, typename T = std::remove_cvref_t<U>> requires storable_str<T, K>
388 T replace_cb(U&& text, auto replacer, size_t offset = 0, size_t maxCount = -1) {
389 if (!regexp_) {
390 return text;
391 }
392 std::vector<str_type> parts;
393 using replacer_ret_t = decltype(replacer(std::declval<std::vector<std::pair<size_t, str_type>>>()));
394 std::list<replacer_ret_t> calcParts;
395
396 size_t delta = 0;
397 const OnigUChar *starto = rt::toChar(text.symbols()), *end = rt::toChar(text.symbols() + text.length()), *at = starto + rt::toLen(offset),
398 *prevStart = starto;
399 RegionPtr region{onig_region_new()};
400
401 for (size_t count = 0; count < maxCount; count++) {
402 int result = onig_search(*this, starto, end, at, end, region.get(), ONIG_OPTION_NONE);
403 if (result >= 0) {
404 delta = rt::fromLen(int(starto + region->beg[0] - prevStart));
405 if (delta) {
406 parts.emplace_back(rt::fromChar(prevStart), delta);
407 }
408 std::vector<std::pair<size_t, str_type>> match;
409 match.reserve(region->num_regs);
410 for (int i = 0; i < region->num_regs; i++) {
411 match.emplace_back(
412 rt::fromLen(region->beg[i]),
413 str_type{rt::fromChar(starto + region->beg[i]), rt::fromLen(region->end[i] - region->beg[i])}
414 );
415 }
416
417 calcParts.emplace_back(replacer(std::move(match)));
418 parts.emplace_back(calcParts.back());
419
420 const OnigUChar* newAt = starto + region->end[0];
421 if (newAt <= at || at >= end) {
422 break;
423 }
424 at = prevStart = newAt;
425 } else {
426 break;
427 }
428 }
429 if (parts.empty()) {
430 // Ничего не заменили, просто форварднем исходный текст.
431 return std::forward<U>(text);
432 }
433 if (at < end) {
434 // Добавим последний кусочек
435 parts.emplace_back(rt::fromChar(at), rt::fromLen(int(end - at)));
436 }
437 return expr_join<K, std::vector<str_type>, 0, false, false>{parts, nullptr};
438 }
439protected:
440 SIMREX_API str_type first_founded_str(str_type text, size_t offset) const;
441 SIMREX_API void all_founded_str(str_type text, size_t offset, size_t maxCount, void(*func)(str_type, void*), void* result) const;
442 SIMREX_API std::vector<std::pair<int, str_type>> parse_replaces(str_type replText, bool substGroups);
443};
444
445using OnigRex = OnigRegexp<u8s>;
446using OnigRexW = OnigRegexp<uws>;
447using OnigRexU = OnigRegexp<u16s>;
448using OnigRexUU = OnigRegexp<u32s>;
449
450} // namespace simrex
Класс для работы с oniguruma регэкспами
Определения onig.h:120
std::vector< std::pair< size_t, T > > first_match(str_type text, size_t offset=0) const
Получить всю информацию о первом найденном вхождении.
Определения onig.h:255
T first_founded(str_type text, size_t offset=0) const
Текст первого найденного вхождения.
Определения onig.h:167
T replace_cb(U &&text, auto replacer, size_t offset=0, size_t maxCount=-1)
Заменить вхождения на текст, возвращаемый из функции обработчика.
Определения onig.h:388
std::vector< T > first_matched(str_type text, size_t offset=0) const
Получить текст первого найденного вхождения вместе с текстами подгрупп.
Определения onig.h:195
std::vector< std::vector< std::pair< size_t, T > > > all_matches(str_type text, size_t offset=0, size_t maxCount=-1) const
Получить всю информацию о всех найденных вхождениях.
Определения onig.h:284
size_t search(str_type text, size_t offset=0)
Поиск положения первого вхождения.
Определения onig.h:147
SIMREX_API size_t count_of(const str_type &text, size_t maxCount=-1, size_t offset=0)
Посчитать количество вхождений.
Определения onig.cpp:6
std::vector< std::vector< T > > all_matched(str_type text, size_t offset=0, size_t maxCount=-1) const
Получить тексты всех найденных вхождений вместе с подгруппами.
Определения onig.h:219
std::vector< T > all_founded(str_type text, size_t offset=0, size_t maxCount=-1) const
Получить тексты всех найденных вхождений, без разделения на подгруппы.
Определения onig.h:179
T replace(U &&text, str_type replText, size_t offset=0, size_t maxCount=-1, bool substGroups=true)
Заменить вхождения на заданный текст.
Определения onig.h:329
OnigRegexp(str_type pattern)
Создает объект Onig Regexp.
Определения onig.h:137