Doxygen
Loading...
Searching...
No Matches
regex.h
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2025 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16#ifndef FREGEX_H
17#define FREGEX_H
18
19#include <iterator>
20#include <memory>
21#include <string>
22#include <string_view>
23#include <vector>
24
25#include "construct.h"
26
27/** Namespace for the regular expression functions */
28namespace reg
29{
30
31class Match;
32
33/** Class representing a regular expression.
34 *
35 * It has a similar API as `std::regex`,
36 * but is much faster (and also somewhat more limited).
37 */
38class Ex
39{
40 public:
41 /** Matching algorithm */
42 enum class Mode
43 {
44 RegEx, /**< full regular expression. */
45 Wildcard /**< simple globbing pattern. */
46 };
47 /** Creates a regular expression object given the pattern as a string.
48 * Two modes of matching are supported: RegEx and Wildcard
49 *
50 * The following special characters are supported in Mode::RegEx mode.
51 * \noop [regex_special_chars]
52 * - `c` matches character `c`
53 * - `.` matches any character
54 * - `^` matches the start of the input
55 * - `$` matches the end of the input
56 * - `<` matches the start of a word
57 * - `>` matches the end of a word
58 * - `[]` matches a set of characters
59 * - `x*` matches a sequence of zero or more `x`'s
60 * - `x+` matches a sequence of one or more `x`'s
61 * - `x?` matches an optional `x`
62 * - `\c` to escape a special character, such as `+`, `[`, `*`, `(`, etc.
63 * - `\t` matches a tab character
64 * - `\n` matches a newline character
65 * - `\r` matches a return character
66 * - `\s` matches any whitespace as defined by `std::isspace()`
67 * - `\d` matches any digit as defined by `std::digit()`
68 * - `\a` matches any alphabetical characters, same as `[a-z_A-Z\x80-\xFF]`
69 * - `\w` matches any alpha numerical character, same as `[a-z_A-Z0-9\x80-\xFF]`
70 * - `\xHH` matches a hexadecimal character, e.g. `\xA0` matches character code 160.
71 * \noop [regex_special_chars]
72 * - `(` matches the start of a capture range
73 * - `)` matches the end of a capture range
74 * \noop [regex_special_chars1]
75 *
76 * A character range can be used to match a character that falls inside a range
77 * (or set of ranges).
78 * Within the opening `[` and closing `]` brackets of a character ranges the following
79 * is supported:
80 * - `^` if at the start of the range, a character matches if it is \e not in the range,
81 * e.g. `[^\d]` matches any character not a digit
82 * - `-` when placed between 2 characters it defines a range from the first character to the second.
83 * any character that falls in the range will match, e.g. [0-9] matches the digit from 0 to 9.
84 * - `\s`, `\d`, `\a`, and `\w` as explained above.
85 *
86 * @note that special characters `.`, `*`, `?`, `$`, `+`, `[` do not have a special
87 * meaning in a character range. `^` only has a special meaning as the first character.
88 *
89 * \noop [regex_special_chars1]
90 * @note capture ranges can be nested. Optional capture ranges `(...)?` are supported but
91 * repeated ranges `(...)*` or `(...)+` are not.
92 * \noop [regex_special_chars2]
93 *
94 * In Wildcard mode `*` is used to match any sequence of zero or more characters.
95 * The character `?` can be used to match an optional character. Character ranges are
96 * also supported, but other characters like `$` and `+` are just treated as
97 * literal characters.
98 * \noop [regex_special_chars2]
99 *
100 */
101 Ex(std::string_view pattern, Mode mode=Mode::RegEx);
102
103 /** Destroys the regular expression object. Frees resources. */
105
106 /** Check if a given string matches this regular expression.
107 * @param str The input string to match against.
108 * @param match The match object to hold the matching results.
109 * @param pos The position in the string at which to start the match.
110 * @returns true iff a match is found. Details are stored in the match object.
111 */
112 bool match(std::string_view str,Match &match,size_t pos=0) const;
113 bool isValid() const;
114 private:
116
117 class Private;
118 std::unique_ptr<Private> p;
119};
120
121/** Object representing the match results of a capture range. */
123{
124 public:
125 /** Creates a match for a single capture range given a non-owning pointer to the string. */
126 SubMatch(std::string_view str) : m_str(str) {}
127
128 /** Returns the position in the string at which the match starts. */
129 size_t position() const { return m_pos; }
130
131 /** Returns the length of the matching part. */
132 size_t length() const { return m_len; }
133
134 /** Returns true if the match is empty (no match). */
135 bool empty() const { return m_len==0; }
136
137 /** Returns the matching part as a string */
138 std::string str() const { return std::string{m_str.substr(m_pos,m_len)}; }
139
140 private:
141 friend class Match;
142 void setStart(size_t pos) { m_pos=pos; }
143 void setEnd(size_t pos) { m_len=pos-m_pos; }
144 void setMatch(size_t pos,size_t len) { m_pos=pos; m_len=len; }
145 size_t m_pos = std::string::npos;
146 size_t m_len = std::string::npos;
147 std::string_view m_str;
148};
149
150/** Object representing the matching results. It consists of an array of
151 * SubMatch objects. The first entry of the array represents the whole match, any
152 * next elements represent each of the capture ranges.
153 *
154 * For example string `@42` and expression `@(\\d+)` will have two
155 * Submatches, match[0] will point to the input string as a whole, and
156 * match[1] will point to the number 42 only.
157 *
158 */
159class Match
160{
161 public:
162 /** Creates an empty match object */
163 Match() {}
164
165 /** Returns the position of the match or std::string::npos if no position is set. */
166 size_t position() const { return m_subMatches[0].position(); }
167
168 /** Returns the position of the match or std::string::npos if no length is set. */
169 size_t length() const { return m_subMatches[0].length(); }
170
171 /** Return a string representing the matching part. */
172 std::string str() const { return std::string{m_subMatches[0].str()}; }
173
174 /** Return the part of the string before the match */
175 SubMatch prefix() const { SubMatch m(m_str); m.setMatch(0,position()); return m; }
176
177 /** Return the part of the string after the match */
179 {
180 SubMatch m(m_str);
181 if (!m_str.empty())
182 {
183 size_t e = position()+length();
184 m.setMatch(e,m_str.length()-e);
185 }
186 return m;
187 }
188
189 /** Returns the number of sub matches available in this match.
190 * Only counts groups that actually matched (trailing unmatched optional groups are excluded). */
191 size_t size() const
192 {
193 size_t s = m_subMatches.size();
194 while (s > 1 && m_subMatches[s-1].position() == std::string::npos) s--;
195 return s;
196 }
197
198 /** Returns the n-th SubMatch object. Note that there is always 1 SubMatch object
199 * representing the whole match.
200 */
201 const SubMatch &operator[](size_t index) const { return m_subMatches[index]; }
202
203 private:
204 friend class Ex;
205 void init(std::string_view str,size_t captureCount)
206 {
207 m_subMatches.clear();
208 m_subMatches.reserve(captureCount+1);
209 for (size_t i=0;i<captureCount+1;i++)
210 {
211 m_subMatches.emplace_back(str);
212 }
213 m_str = str;
214 }
215 void startCapture(size_t groupId,size_t index)
216 {
217 if (groupId < m_subMatches.size())
218 {
219 m_subMatches[groupId].setStart(index);
220 }
221 }
222 void endCapture(size_t groupId,size_t index)
223 {
224 if (groupId < m_subMatches.size())
225 {
226 if (index>=m_subMatches[groupId].position())
227 {
228 m_subMatches[groupId].setEnd(index);
229 }
230 }
231 }
232 void setMatch(size_t pos,size_t len)
233 {
234 // Always set the whole match
235 m_subMatches[0].setMatch(pos,len);
236 }
237
238 std::vector<SubMatch> m_subMatches;
239 std::string_view m_str;
240};
241
242/** Class to iterate through matches.
243 */
245{
246 public:
248 using difference_type = std::ptrdiff_t;
251 using iterator_category = std::forward_iterator_tag;
252
253 /** Creates an end-of-sequence iterator */
255
256 /** Creates an iterator for input string \a str, using regular expression \a re to search.
257 * @note the string and regular expression objects should remain valid while iterating.
258 */
259 Iterator(std::string_view str, const Ex &re, size_t pos=0)
260 : m_str(str), m_re(&re), m_pos(pos) { findNext(); }
261
262 // Iterator holds pointers, so prevent temporaries to be passed as string or
263 // regular expression
264 Iterator(std::string &&str, const Ex &re) = delete;
265 Iterator(const std::string &str, Ex &&re) = delete;
266 Iterator(std::string &&str, Ex &&re) = delete;
267
268 /** Returns true if the iterators point to the same match (or both are end-of-sequence iterators) */
269 bool operator==(const Iterator &rhs) const { return rhs.m_pos==m_pos; }
270
271 /** Returns true if the iterators are not pointing to the same match */
272 bool operator!=(const Iterator &rhs) const { return rhs.m_pos!=m_pos; }
273
274 /** Returns a reference to the current match */
275 const value_type &operator*() const { return m_match; }
276
277 /** Returns a pointer to the current match */
278 const value_type *operator->() const { return &m_match; }
279
280 /** Advances the iterator to the next match. */
281 Iterator &operator++() { findNext(); return *this; }
282
283 private:
284 void findNext()
285 {
286 if (!m_re || m_str.empty()) { m_pos=std::string::npos; return; } // end marker
288 {
289 m_pos=m_match.position()+m_match.length(); // update m_pos to point beyond last match
290 }
291 else // no more matches, make the iterator point to the 'end-of-sequence'
292 {
293 m_pos=std::string::npos;
294 }
295 }
296 std::string_view m_str;
297 const Ex *m_re = nullptr;
298 size_t m_pos = std::string::npos;
300};
301
302/** Search in a given string \a str starting at position \a pos for a match against regular expression \a re.
303 * Returns true iff a match was found.
304 * Details of what part of the string has matched is returned via the \a match object.
305 *
306 * An example to show how to match all identifiers in a string.
307 * @code
308 * static reg::Ex re(R"(\a\w*)");
309 * std::string = u8"void(Func是<B_C::Códe42>(42));";
310 * while (reg::search(str,match,re,pos))
311 * {
312 * std::cout << match.str() << std::endl;
313 * pos=match.position()+match.length();
314 * }
315 * @endcode
316 * produces:
317 * @code
318 * void
319 * Func是
320 * B_C
321 * Códe42
322 * @endcode
323 *
324 * @see Ex::Ex() for details on the regular expression patterns.
325 */
326bool search(std::string_view str,Match &match,const Ex &re,size_t pos=0);
327
328/** Search in a given string \a str starting at position \a pos for a match against regular expression \a re.
329 * Returns true iff a match was found.
330 */
331bool search(std::string_view str,const Ex &re,size_t pos=0);
332
333/** Matches a given string \a str for a match against regular expression \a re.
334 * Returns true iff a match was found for the whole string.
335 * Any capture groups are returned via the \a match object.
336 */
337bool match(std::string_view str,Match &match,const Ex &re);
338
339/** Matches a given string \a str for a match against regular expression \a re.
340 * Returns true iff a match was found for the whole string.
341 */
342bool match(std::string_view str,const Ex &re);
343
344/** Searching in a given input string \a for parts that match regular expression \a re and
345 * replaces those parts by string \a replacement.
346 */
347std::string replace(std::string_view str,const Ex &re,std::string_view replacement);
348
349} // namespace
350
351#endif
Private members of a regular expression.
Definition regex.cpp:173
Class representing a regular expression.
Definition regex.h:39
~Ex()
Destroys the regular expression object.
std::unique_ptr< Private > p
Definition regex.h:118
bool match(std::string_view str, Match &match, size_t pos=0) const
Check if a given string matches this regular expression.
Definition regex.cpp:808
Ex(std::string_view pattern, Mode mode=Mode::RegEx)
Creates a regular expression object given the pattern as a string.
Definition regex.cpp:796
Mode
Matching algorithm.
Definition regex.h:43
@ RegEx
full regular expression.
Definition regex.h:44
bool isValid() const
Definition regex.cpp:843
Iterator(std::string &&str, const Ex &re)=delete
const value_type & operator*() const
Returns a reference to the current match.
Definition regex.h:275
value_type & reference
Definition regex.h:250
Iterator(std::string &&str, Ex &&re)=delete
Iterator & operator++()
Advances the iterator to the next match.
Definition regex.h:281
size_t m_pos
Definition regex.h:298
Iterator(const std::string &str, Ex &&re)=delete
std::forward_iterator_tag iterator_category
Definition regex.h:251
std::ptrdiff_t difference_type
Definition regex.h:248
Iterator()
Creates an end-of-sequence iterator.
Definition regex.h:254
Match value_type
Definition regex.h:247
const value_type * operator->() const
Returns a pointer to the current match.
Definition regex.h:278
std::string_view m_str
Definition regex.h:296
Match m_match
Definition regex.h:299
Iterator(std::string_view str, const Ex &re, size_t pos=0)
Creates an iterator for input string str, using regular expression re to search.
Definition regex.h:259
bool operator==(const Iterator &rhs) const
Returns true if the iterators point to the same match (or both are end-of-sequence iterators).
Definition regex.h:269
value_type * pointer
Definition regex.h:249
const Ex * m_re
Definition regex.h:297
void findNext()
Definition regex.h:284
bool operator!=(const Iterator &rhs) const
Returns true if the iterators are not pointing to the same match.
Definition regex.h:272
Object representing the matching results.
Definition regex.h:160
friend class Ex
Definition regex.h:204
void endCapture(size_t groupId, size_t index)
Definition regex.h:222
Match()
Creates an empty match object.
Definition regex.h:163
std::string_view m_str
Definition regex.h:239
void init(std::string_view str, size_t captureCount)
Definition regex.h:205
void startCapture(size_t groupId, size_t index)
Definition regex.h:215
const SubMatch & operator[](size_t index) const
Returns the n-th SubMatch object.
Definition regex.h:201
size_t size() const
Returns the number of sub matches available in this match.
Definition regex.h:191
SubMatch prefix() const
Return the part of the string before the match.
Definition regex.h:175
size_t position() const
Returns the position of the match or std::string::npos if no position is set.
Definition regex.h:166
std::string str() const
Return a string representing the matching part.
Definition regex.h:172
std::vector< SubMatch > m_subMatches
Definition regex.h:238
void setMatch(size_t pos, size_t len)
Definition regex.h:232
SubMatch suffix() const
Return the part of the string after the match.
Definition regex.h:178
size_t length() const
Returns the position of the match or std::string::npos if no length is set.
Definition regex.h:169
Object representing the match results of a capture range.
Definition regex.h:123
size_t length() const
Returns the length of the matching part.
Definition regex.h:132
void setEnd(size_t pos)
Definition regex.h:143
void setStart(size_t pos)
Definition regex.h:142
bool empty() const
Returns true if the match is empty (no match).
Definition regex.h:135
void setMatch(size_t pos, size_t len)
Definition regex.h:144
size_t m_len
Definition regex.h:146
size_t m_pos
Definition regex.h:145
std::string_view m_str
Definition regex.h:147
friend class Match
Definition regex.h:141
SubMatch(std::string_view str)
Creates a match for a single capture range given a non-owning pointer to the string.
Definition regex.h:126
size_t position() const
Returns the position in the string at which the match starts.
Definition regex.h:129
std::string str() const
Returns the matching part as a string.
Definition regex.h:138
#define NON_COPYABLE(cls)
Macro to help implementing the rule of 5 for a non-copyable & movable class.
Definition construct.h:37
Namespace for the regular expression functions.
Definition regex.cpp:34
bool search(std::string_view str, Match &match, const Ex &re, size_t pos)
Search in a given string str starting at position pos for a match against regular expression re.
Definition regex.cpp:850
std::string replace(std::string_view str, const Ex &re, std::string_view replacement)
Searching in a given input string for parts that match regular expression re and replaces those parts...
Definition regex.cpp:872
bool match(std::string_view str, Match &match, const Ex &re)
Matches a given string str for a match against regular expression re.
Definition regex.cpp:861