1// Copyright (C) 2020 Giuseppe D'Angelo <dangelog@gmail.com>.
2// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
3// Copyright (C) 2021 The Qt Company Ltd.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#include "qregularexpression.h"
7
8#include <QtCore/qcoreapplication.h>
9#include <QtCore/qhashfunctions.h>
10#include <QtCore/qlist.h>
11#include <QtCore/qmutex.h>
12#include <QtCore/qstringlist.h>
13#include <QtCore/qdebug.h>
14#include <QtCore/qglobal.h>
15#include <QtCore/qatomic.h>
16#include <QtCore/qdatastream.h>
17
18#if defined(Q_OS_MACOS)
19#include <QtCore/private/qcore_mac_p.h>
20#endif
21
22#define PCRE2_CODE_UNIT_WIDTH 16
23
24#include <pcre2.h>
25
26QT_BEGIN_NAMESPACE
27
28using namespace Qt::StringLiterals;
29
30/*!
31 \class QRegularExpression
32 \inmodule QtCore
33 \reentrant
34
35 \brief The QRegularExpression class provides pattern matching using regular
36 expressions.
37
38 \since 5.0
39
40 \ingroup tools
41 \ingroup shared
42
43 \keyword regular expression
44
45 Regular expressions, or \e{regexps}, are a very powerful tool to handle
46 strings and texts. This is useful in many contexts, e.g.,
47
48 \table
49 \row \li Validation
50 \li A regexp can test whether a substring meets some criteria,
51 e.g. is an integer or contains no whitespace.
52 \row \li Searching
53 \li A regexp provides more powerful pattern matching than
54 simple substring matching, e.g., match one of the words
55 \e{mail}, \e{letter} or \e{correspondence}, but none of the
56 words \e{email}, \e{mailman}, \e{mailer}, \e{letterbox}, etc.
57 \row \li Search and Replace
58 \li A regexp can replace all occurrences of a substring with a
59 different substring, e.g., replace all occurrences of \e{&}
60 with \e{\&amp;} except where the \e{&} is already followed by
61 an \e{amp;}.
62 \row \li String Splitting
63 \li A regexp can be used to identify where a string should be
64 split apart, e.g. splitting tab-delimited strings.
65 \endtable
66
67 This document is by no means a complete reference to pattern matching using
68 regular expressions, and the following parts will require the reader to
69 have some basic knowledge about Perl-like regular expressions and their
70 pattern syntax.
71
72 Good references about regular expressions include:
73
74 \list
75 \li \e {Mastering Regular Expressions} (Third Edition) by Jeffrey E. F.
76 Friedl, ISBN 0-596-52812-4;
77 \li the \l{https://pcre.org/original/doc/html/pcrepattern.html}
78 {pcrepattern(3)} man page, describing the pattern syntax supported by PCRE
79 (the reference implementation of Perl-compatible regular expressions);
80 \li the \l{http://perldoc.perl.org/perlre.html} {Perl's regular expression
81 documentation} and the \l{http://perldoc.perl.org/perlretut.html} {Perl's
82 regular expression tutorial}.
83 \endlist
84
85 \tableofcontents
86
87 \section1 Introduction
88
89 QRegularExpression implements Perl-compatible regular expressions. It fully
90 supports Unicode. For an overview of the regular expression syntax
91 supported by QRegularExpression, please refer to the aforementioned
92 pcrepattern(3) man page. A regular expression is made up of two things: a
93 \b{pattern string} and a set of \b{pattern options} that change the
94 meaning of the pattern string.
95
96 You can set the pattern string by passing a string to the QRegularExpression
97 constructor:
98
99 \snippet code/src_corelib_text_qregularexpression.cpp 0
100
101 This sets the pattern string to \c{a pattern}. You can also use the
102 setPattern() function to set a pattern on an existing QRegularExpression
103 object:
104
105 \snippet code/src_corelib_text_qregularexpression.cpp 1
106
107 Note that due to C++ literal strings rules, you must escape all backslashes
108 inside the pattern string with another backslash:
109
110 \snippet code/src_corelib_text_qregularexpression.cpp 2
111
112 Alternatively, you can use a
113 \l {https://en.cppreference.com/w/cpp/language/string_literal} {raw string literal},
114 in which case you don't need to escape backslashes in the pattern, all characters
115 between \c {R"(...)"} are considered raw characters. As you can see in the following
116 example, this simplifies writing patterns:
117
118 \snippet code/src_corelib_text_qregularexpression.cpp 35
119
120 The pattern() function returns the pattern that is currently set for a
121 QRegularExpression object:
122
123 \snippet code/src_corelib_text_qregularexpression.cpp 3
124
125 \section1 Pattern Options
126
127 The meaning of the pattern string can be modified by setting one or more
128 \e{pattern options}. For instance, it is possible to set a pattern to match
129 case insensitively by setting the QRegularExpression::CaseInsensitiveOption.
130
131 You can set the options by passing them to the QRegularExpression
132 constructor, as in:
133
134 \snippet code/src_corelib_text_qregularexpression.cpp 4
135
136 Alternatively, you can use the setPatternOptions() function on an existing
137 QRegularExpressionObject:
138
139 \snippet code/src_corelib_text_qregularexpression.cpp 5
140
141 It is possible to get the pattern options currently set on a
142 QRegularExpression object by using the patternOptions() function:
143
144 \snippet code/src_corelib_text_qregularexpression.cpp 6
145
146 Please refer to the QRegularExpression::PatternOption enum documentation for
147 more information about each pattern option.
148
149 \section1 Match Type and Match Options
150
151 The last two arguments of the match() and the globalMatch() functions set
152 the match type and the match options. The match type is a value of the
153 QRegularExpression::MatchType enum; the "traditional" matching algorithm is
154 chosen by using the NormalMatch match type (the default). It is also
155 possible to enable partial matching of the regular expression against a
156 subject string: see the \l{partial matching} section for more details.
157
158 The match options are a set of one or more QRegularExpression::MatchOption
159 values. They change the way a specific match of a regular expression
160 against a subject string is done. Please refer to the
161 QRegularExpression::MatchOption enum documentation for more details.
162
163 \target normal matching
164 \section1 Normal Matching
165
166 In order to perform a match you can simply invoke the match() function
167 passing a string to match against. We refer to this string as the
168 \e{subject string}. The result of the match() function is a
169 QRegularExpressionMatch object that can be used to inspect the results of
170 the match. For instance:
171
172 \snippet code/src_corelib_text_qregularexpression.cpp 7
173
174 If a match is successful, the (implicit) capturing group number 0 can be
175 used to retrieve the substring matched by the entire pattern (see also the
176 section about \l{extracting captured substrings}):
177
178 \snippet code/src_corelib_text_qregularexpression.cpp 8
179
180 It's also possible to start a match at an arbitrary offset inside the
181 subject string by passing the offset as an argument of the
182 match() function. In the following example \c{"12 abc"}
183 is not matched because the match is started at offset 1:
184
185 \snippet code/src_corelib_text_qregularexpression.cpp 9
186
187 \target extracting captured substrings
188 \section2 Extracting captured substrings
189
190 The QRegularExpressionMatch object contains also information about the
191 substrings captured by the capturing groups in the pattern string. The
192 \l{QRegularExpressionMatch::}{captured()} function will return the string
193 captured by the n-th capturing group:
194
195 \snippet code/src_corelib_text_qregularexpression.cpp 10
196
197 Capturing groups in the pattern are numbered starting from 1, and the
198 implicit capturing group 0 is used to capture the substring that matched
199 the entire pattern.
200
201 It's also possible to retrieve the starting and the ending offsets (inside
202 the subject string) of each captured substring, by using the
203 \l{QRegularExpressionMatch::}{capturedStart()} and the
204 \l{QRegularExpressionMatch::}{capturedEnd()} functions:
205
206 \snippet code/src_corelib_text_qregularexpression.cpp 11
207
208 All of these functions have an overload taking a QString as a parameter
209 in order to extract \e{named} captured substrings. For instance:
210
211 \snippet code/src_corelib_text_qregularexpression.cpp 12
212
213 \target global matching
214 \section1 Global Matching
215
216 \e{Global matching} is useful to find all the occurrences of a given
217 regular expression inside a subject string. Suppose that we want to extract
218 all the words from a given string, where a word is a substring matching
219 the pattern \c{\w+}.
220
221 QRegularExpression::globalMatch returns a QRegularExpressionMatchIterator,
222 which is a Java-like forward iterator that can be used to iterate over the
223 results. For instance:
224
225 \snippet code/src_corelib_text_qregularexpression.cpp 13
226
227 Since it's a Java-like iterator, the QRegularExpressionMatchIterator will
228 point immediately before the first result. Every result is returned as a
229 QRegularExpressionMatch object. The
230 \l{QRegularExpressionMatchIterator::}{hasNext()} function will return true
231 if there's at least one more result, and
232 \l{QRegularExpressionMatchIterator::}{next()} will return the next result
233 and advance the iterator. Continuing from the previous example:
234
235 \snippet code/src_corelib_text_qregularexpression.cpp 14
236
237 You can also use \l{QRegularExpressionMatchIterator::}{peekNext()} to get
238 the next result without advancing the iterator.
239
240 It is also possible to simply use the result of
241 QRegularExpression::globalMatch in a range-based for loop, for instance
242 like this:
243
244 \snippet code/src_corelib_text_qregularexpression.cpp 34
245
246 It is possible to pass a starting offset and one or more match options to
247 the globalMatch() function, exactly like normal matching with match().
248
249 \target partial matching
250 \section1 Partial Matching
251
252 A \e{partial match} is obtained when the end of the subject string is
253 reached, but more characters are needed to successfully complete the match.
254 Note that a partial match is usually much more inefficient than a normal
255 match because many optimizations of the matching algorithm cannot be
256 employed.
257
258 A partial match must be explicitly requested by specifying a match type of
259 PartialPreferCompleteMatch or PartialPreferFirstMatch when calling
260 QRegularExpression::match or QRegularExpression::globalMatch. If a partial
261 match is found, then calling the \l{QRegularExpressionMatch::}{hasMatch()}
262 function on the QRegularExpressionMatch object returned by match() will
263 return \c{false}, but \l{QRegularExpressionMatch::}{hasPartialMatch()} will return
264 \c{true}.
265
266 When a partial match is found, no captured substrings are returned, and the
267 (implicit) capturing group 0 corresponding to the whole match captures the
268 partially matched substring of the subject string.
269
270 Note that asking for a partial match can still lead to a complete match, if
271 one is found; in this case, \l{QRegularExpressionMatch::}{hasMatch()} will
272 return \c{true} and \l{QRegularExpressionMatch::}{hasPartialMatch()}
273 \c{false}. It never happens that a QRegularExpressionMatch reports both a
274 partial and a complete match.
275
276 Partial matching is mainly useful in two scenarios: validating user input
277 in real time and incremental/multi-segment matching.
278
279 \target validating user input
280 \section2 Validating user input
281
282 Suppose that we would like the user to input a date in a specific
283 format, for instance "MMM dd, yyyy". We can check the input validity with
284 a pattern like:
285
286 \c{^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d\d?, \d\d\d\d$}
287
288 (This pattern doesn't catch invalid days, but let's keep it for the
289 example's purposes).
290
291 We would like to validate the input with this regular expression \e{while}
292 the user is typing it, so that we can report an error in the input as soon
293 as it is committed (for instance, the user typed the wrong key). In order
294 to do so we must distinguish three cases:
295
296 \list
297 \li the input cannot possibly match the regular expression;
298 \li the input does match the regular expression;
299 \li the input does not match the regular expression right now,
300 but it will if more characters will be added to it.
301 \endlist
302
303 Note that these three cases represent exactly the possible states of a
304 QValidator (see the QValidator::State enum).
305
306 In particular, in the last case we want the regular expression engine to
307 report a partial match: we are successfully matching the pattern against
308 the subject string but the matching cannot continue because the end of the
309 subject is encountered. Notice, however, that the matching algorithm should
310 continue and try all possibilities, and in case a complete (non-partial)
311 match is found, then this one should be reported, and the input string
312 accepted as fully valid.
313
314 This behavior is implemented by the PartialPreferCompleteMatch match type.
315 For instance:
316
317 \snippet code/src_corelib_text_qregularexpression.cpp 15
318
319 If matching the same regular expression against the subject string leads to
320 a complete match, it is reported as usual:
321
322 \snippet code/src_corelib_text_qregularexpression.cpp 16
323
324 Another example with a different pattern, showing the behavior of
325 preferring a complete match over a partial one:
326
327 \snippet code/src_corelib_text_qregularexpression.cpp 17
328
329 In this case, the subpattern \c{abc\\w+X} partially matches the subject
330 string; however, the subpattern \c{def} matches the subject string
331 completely, and therefore a complete match is reported.
332
333 If multiple partial matches are found when matching (but no complete
334 match), then the QRegularExpressionMatch object will report the first one
335 that is found. For instance:
336
337 \snippet code/src_corelib_text_qregularexpression.cpp 18
338
339 \section2 Incremental/multi-segment matching
340
341 Incremental matching is another use case of partial matching. Suppose that
342 we want to find the occurrences of a regular expression inside a large text
343 (that is, substrings matching the regular expression). In order to do so we
344 would like to "feed" the large text to the regular expression engines in
345 smaller chunks. The obvious problem is what happens if the substring that
346 matches the regular expression spans across two or more chunks.
347
348 In this case, the regular expression engine should report a partial match,
349 so that we can match again adding new data and (eventually) get a complete
350 match. This implies that the regular expression engine may assume that
351 there are other characters \e{beyond the end} of the subject string. This
352 is not to be taken literally -- the engine will never try to access
353 any character after the last one in the subject.
354
355 QRegularExpression implements this behavior when using the
356 PartialPreferFirstMatch match type. This match type reports a partial match
357 as soon as it is found, and other match alternatives are not tried
358 (even if they could lead to a complete match). For instance:
359
360 \snippet code/src_corelib_text_qregularexpression.cpp 19
361
362 This happens because when matching the first branch of the alternation
363 operator a partial match is found, and therefore matching stops, without
364 trying the second branch. Another example:
365
366 \snippet code/src_corelib_text_qregularexpression.cpp 20
367
368 This shows what could seem a counterintuitive behavior of quantifiers:
369 since \c{?} is greedy, then the engine tries first to continue the match
370 after having matched \c{"abc"}; but then the matching reaches the end of the
371 subject string, and therefore a partial match is reported. This is
372 even more surprising in the following example:
373
374 \snippet code/src_corelib_text_qregularexpression.cpp 21
375
376 It's easy to understand this behavior if we remember that the engine
377 expects the subject string to be only a substring of the whole text we're
378 looking for a match into (that is, how we said before, that the engine
379 assumes that there are other characters beyond the end of the subject
380 string).
381
382 Since the \c{*} quantifier is greedy, then reporting a complete match could
383 be an error, because after the current subject \c{"abc"} there may be other
384 occurrences of \c{"abc"}. For instance, the complete text could have been
385 "abcabcX", and therefore the \e{right} match to report (in the complete
386 text) would have been \c{"abcabc"}; by matching only against the leading
387 \c{"abc"} we instead get a partial match.
388
389 \section1 Error Handling
390
391 It is possible for a QRegularExpression object to be invalid because of
392 syntax errors in the pattern string. The isValid() function will return
393 true if the regular expression is valid, or false otherwise:
394
395 \snippet code/src_corelib_text_qregularexpression.cpp 22
396
397 You can get more information about the specific error by calling the
398 errorString() function; moreover, the patternErrorOffset() function
399 will return the offset inside the pattern string
400
401 \snippet code/src_corelib_text_qregularexpression.cpp 23
402
403 If a match is attempted with an invalid QRegularExpression, then the
404 returned QRegularExpressionMatch object will be invalid as well (that is,
405 its \l{QRegularExpressionMatch::}{isValid()} function will return false).
406 The same applies for attempting a global match.
407
408 \section1 Unsupported Perl-compatible Regular Expressions Features
409
410 QRegularExpression does not support all the features available in
411 Perl-compatible regular expressions. The most notable one is the fact that
412 duplicated names for capturing groups are not supported, and using them can
413 lead to undefined behavior.
414
415 This may change in a future version of Qt.
416
417 \section1 Debugging Code that Uses QRegularExpression
418
419 QRegularExpression internally uses a just in time compiler (JIT) to
420 optimize the execution of the matching algorithm. The JIT makes extensive
421 usage of self-modifying code, which can lead debugging tools such as
422 Valgrind to crash. You must enable all checks for self-modifying code if
423 you want to debug programs using QRegularExpression (for instance, Valgrind's
424 \c{--smc-check} command line option). The downside of enabling such checks
425 is that your program will run considerably slower.
426
427 To avoid that, the JIT is disabled by default if you compile Qt in debug
428 mode. It is possible to override the default and enable or disable the JIT
429 usage (both in debug or release mode) by setting the
430 \c{QT_ENABLE_REGEXP_JIT} environment variable to a non-zero or zero value
431 respectively.
432
433 \sa QRegularExpressionMatch, QRegularExpressionMatchIterator
434*/
435
436/*!
437 \class QRegularExpressionMatch
438 \inmodule QtCore
439 \reentrant
440
441 \brief The QRegularExpressionMatch class provides the results of a matching
442 a QRegularExpression against a string.
443
444 \since 5.0
445
446 \ingroup tools
447 \ingroup shared
448
449 \keyword regular expression match
450
451 A QRegularExpressionMatch object can be obtained by calling the
452 QRegularExpression::match() function, or as a single result of a global
453 match from a QRegularExpressionMatchIterator.
454
455 The success or the failure of a match attempt can be inspected by calling
456 the hasMatch() function. QRegularExpressionMatch also reports a successful
457 partial match through the hasPartialMatch() function.
458
459 In addition, QRegularExpressionMatch returns the substrings captured by the
460 capturing groups in the pattern string. The implicit capturing group with
461 index 0 captures the result of the whole match. The captured() function
462 returns each substring captured, either by the capturing group's index or
463 by its name:
464
465 \snippet code/src_corelib_text_qregularexpression.cpp 29
466
467 For each captured substring it is possible to query its starting and ending
468 offsets in the subject string by calling the capturedStart() and the
469 capturedEnd() function, respectively. The length of each captured
470 substring is available using the capturedLength() function.
471
472 The convenience function capturedTexts() will return \e{all} the captured
473 substrings at once (including the substring matched by the entire pattern)
474 in the order they have been captured by capturing groups; that is,
475 \c{captured(i) == capturedTexts().at(i)}.
476
477 You can retrieve the QRegularExpression object the subject string was
478 matched against by calling the regularExpression() function; the
479 match type and the match options are available as well by calling
480 the matchType() and the matchOptions() respectively.
481
482 Please refer to the QRegularExpression documentation for more information
483 about the Qt regular expression classes.
484
485 \sa QRegularExpression
486*/
487
488/*!
489 \class QRegularExpressionMatchIterator
490 \inmodule QtCore
491 \reentrant
492
493 \brief The QRegularExpressionMatchIterator class provides an iterator on
494 the results of a global match of a QRegularExpression object against a string.
495
496 \since 5.0
497
498 \ingroup tools
499 \ingroup shared
500
501 \keyword regular expression iterator
502
503 A QRegularExpressionMatchIterator object is a forward only Java-like
504 iterator; it can be obtained by calling the
505 QRegularExpression::globalMatch() function. A new
506 QRegularExpressionMatchIterator will be positioned before the first result.
507 You can then call the hasNext() function to check if there are more
508 results available; if so, the next() function will return the next
509 result and advance the iterator.
510
511 Each result is a QRegularExpressionMatch object holding all the information
512 for that result (including captured substrings).
513
514 For instance:
515
516 \snippet code/src_corelib_text_qregularexpression.cpp 30
517
518 Moreover, QRegularExpressionMatchIterator offers a peekNext() function
519 to get the next result \e{without} advancing the iterator.
520
521 Starting with Qt 6.0, it is also possible to simply use the result of
522 QRegularExpression::globalMatch in a range-based for loop, for instance
523 like this:
524
525 \snippet code/src_corelib_text_qregularexpression.cpp 34
526
527 You can retrieve the QRegularExpression object the subject string was
528 matched against by calling the regularExpression() function; the
529 match type and the match options are available as well by calling
530 the matchType() and the matchOptions() respectively.
531
532 Please refer to the QRegularExpression documentation for more information
533 about the Qt regular expression classes.
534
535 \sa QRegularExpression, QRegularExpressionMatch
536*/
537
538
539/*!
540 \enum QRegularExpression::PatternOption
541
542 The PatternOption enum defines modifiers to the way the pattern string
543 should be interpreted, and therefore the way the pattern matches against a
544 subject string.
545
546 \value NoPatternOption
547 No pattern options are set.
548
549 \value CaseInsensitiveOption
550 The pattern should match against the subject string in a case
551 insensitive way. This option corresponds to the /i modifier in Perl
552 regular expressions.
553
554 \value DotMatchesEverythingOption
555 The dot metacharacter (\c{.}) in the pattern string is allowed to match
556 any character in the subject string, including newlines (normally, the
557 dot does not match newlines). This option corresponds to the \c{/s}
558 modifier in Perl regular expressions.
559
560 \value MultilineOption
561 The caret (\c{^}) and the dollar (\c{$}) metacharacters in the pattern
562 string are allowed to match, respectively, immediately after and
563 immediately before any newline in the subject string, as well as at the
564 very beginning and at the very end of the subject string. This option
565 corresponds to the \c{/m} modifier in Perl regular expressions.
566
567 \value ExtendedPatternSyntaxOption
568 Any whitespace in the pattern string which is not escaped and outside a
569 character class is ignored. Moreover, an unescaped sharp (\b{#})
570 outside a character class causes all the following characters, until
571 the first newline (included), to be ignored. This can be used to
572 increase the readability of a pattern string as well as put comments
573 inside regular expressions; this is particularly useful if the pattern
574 string is loaded from a file or written by the user, because in C++
575 code it is always possible to use the rules for string literals to put
576 comments outside the pattern string. This option corresponds to the \c{/x}
577 modifier in Perl regular expressions.
578
579 \value InvertedGreedinessOption
580 The greediness of the quantifiers is inverted: \c{*}, \c{+}, \c{?},
581 \c{{m,n}}, etc. become lazy, while their lazy versions (\c{*?},
582 \c{+?}, \c{??}, \c{{m,n}?}, etc.) become greedy. There is no equivalent
583 for this option in Perl regular expressions.
584
585 \value DontCaptureOption
586 The non-named capturing groups do not capture substrings; named
587 capturing groups still work as intended, as well as the implicit
588 capturing group number 0 corresponding to the entire match. There is no
589 equivalent for this option in Perl regular expressions.
590
591 \value UseUnicodePropertiesOption
592 The meaning of the \c{\w}, \c{\d}, etc., character classes, as well as
593 the meaning of their counterparts (\c{\W}, \c{\D}, etc.), is changed
594 from matching ASCII characters only to matching any character with the
595 corresponding Unicode property. For instance, \c{\d} is changed to
596 match any character with the Unicode Nd (decimal digit) property;
597 \c{\w} to match any character with either the Unicode L (letter) or N
598 (digit) property, plus underscore, and so on. This option corresponds
599 to the \c{/u} modifier in Perl regular expressions.
600*/
601
602/*!
603 \enum QRegularExpression::MatchType
604
605 The MatchType enum defines the type of the match that should be attempted
606 against the subject string.
607
608 \value NormalMatch
609 A normal match is done.
610
611 \value PartialPreferCompleteMatch
612 The pattern string is matched partially against the subject string. If
613 a partial match is found, then it is recorded, and other matching
614 alternatives are tried as usual. If a complete match is then found,
615 then it's preferred to the partial match; in this case only the
616 complete match is reported. If instead no complete match is found (but
617 only the partial one), then the partial one is reported.
618
619 \value PartialPreferFirstMatch
620 The pattern string is matched partially against the subject string. If
621 a partial match is found, then matching stops and the partial match is
622 reported. In this case, other matching alternatives (potentially
623 leading to a complete match) are not tried. Moreover, this match type
624 assumes that the subject string only a substring of a larger text, and
625 that (in this text) there are other characters beyond the end of the
626 subject string. This can lead to surprising results; see the discussion
627 in the \l{partial matching} section for more details.
628
629 \value NoMatch
630 No matching is done. This value is returned as the match type by a
631 default constructed QRegularExpressionMatch or
632 QRegularExpressionMatchIterator. Using this match type is not very
633 useful for the user, as no matching ever happens. This enum value
634 has been introduced in Qt 5.1.
635*/
636
637/*!
638 \enum QRegularExpression::MatchOption
639
640 \value NoMatchOption
641 No match options are set.
642
643 \value AnchoredMatchOption
644 Use AnchorAtOffsetMatchOption instead.
645
646 \value AnchorAtOffsetMatchOption
647 The match is constrained to start exactly at the offset passed to
648 match() in order to be successful, even if the pattern string does not
649 contain any metacharacter that anchors the match at that point.
650 Note that passing this option does not anchor the end of the match
651 to the end of the subject; if you want to fully anchor a regular
652 expression, use anchoredPattern().
653 This enum value has been introduced in Qt 6.0.
654
655 \value DontCheckSubjectStringMatchOption
656 The subject string is not checked for UTF-16 validity before
657 attempting a match. Use this option with extreme caution, as
658 attempting to match an invalid string may crash the program and/or
659 constitute a security issue. This enum value has been introduced in
660 Qt 5.4.
661*/
662
663/*!
664 \internal
665*/
666static int convertToPcreOptions(QRegularExpression::PatternOptions patternOptions)
667{
668 int options = 0;
669
670 if (patternOptions & QRegularExpression::CaseInsensitiveOption)
671 options |= PCRE2_CASELESS;
672 if (patternOptions & QRegularExpression::DotMatchesEverythingOption)
673 options |= PCRE2_DOTALL;
674 if (patternOptions & QRegularExpression::MultilineOption)
675 options |= PCRE2_MULTILINE;
676 if (patternOptions & QRegularExpression::ExtendedPatternSyntaxOption)
677 options |= PCRE2_EXTENDED;
678 if (patternOptions & QRegularExpression::InvertedGreedinessOption)
679 options |= PCRE2_UNGREEDY;
680 if (patternOptions & QRegularExpression::DontCaptureOption)
681 options |= PCRE2_NO_AUTO_CAPTURE;
682 if (patternOptions & QRegularExpression::UseUnicodePropertiesOption)
683 options |= PCRE2_UCP;
684
685 return options;
686}
687
688/*!
689 \internal
690*/
691static int convertToPcreOptions(QRegularExpression::MatchOptions matchOptions)
692{
693 int options = 0;
694
695 if (matchOptions & QRegularExpression::AnchorAtOffsetMatchOption)
696 options |= PCRE2_ANCHORED;
697 if (matchOptions & QRegularExpression::DontCheckSubjectStringMatchOption)
698 options |= PCRE2_NO_UTF_CHECK;
699
700 return options;
701}
702
703struct QRegularExpressionPrivate : QSharedData
704{
705 QRegularExpressionPrivate();
706 ~QRegularExpressionPrivate();
707 QRegularExpressionPrivate(const QRegularExpressionPrivate &other);
708
709 void cleanCompiledPattern();
710 void compilePattern();
711 void getPatternInfo();
712 void optimizePattern();
713
714 enum CheckSubjectStringOption {
715 CheckSubjectString,
716 DontCheckSubjectString
717 };
718
719 void doMatch(QRegularExpressionMatchPrivate *priv,
720 qsizetype offset,
721 CheckSubjectStringOption checkSubjectStringOption = CheckSubjectString,
722 const QRegularExpressionMatchPrivate *previous = nullptr) const;
723
724 int captureIndexForName(QStringView name) const;
725
726 // sizeof(QSharedData) == 4, so start our members with an enum
727 QRegularExpression::PatternOptions patternOptions;
728 QString pattern;
729
730 // *All* of the following members are managed while holding this mutex,
731 // except for isDirty which is set to true by QRegularExpression setters
732 // (right after a detach happened).
733 mutable QMutex mutex;
734
735 // The PCRE code pointer is reference-counted by the QRegularExpressionPrivate
736 // objects themselves; when the private is copied (i.e. a detach happened)
737 // it is set to nullptr
738 pcre2_code_16 *compiledPattern;
739 int errorCode;
740 qsizetype errorOffset;
741 int capturingCount;
742 bool usingCrLfNewlines;
743 bool isDirty;
744};
745
746struct QRegularExpressionMatchPrivate : QSharedData
747{
748 QRegularExpressionMatchPrivate(const QRegularExpression &re,
749 const QString &subjectStorage,
750 QStringView subject,
751 QRegularExpression::MatchType matchType,
752 QRegularExpression::MatchOptions matchOptions);
753
754 QRegularExpressionMatch nextMatch() const;
755
756 const QRegularExpression regularExpression;
757
758 // subject is what we match upon. If we've been asked to match over
759 // a QString, then subjectStorage is a copy of that string
760 // (so that it's kept alive by us)
761 const QString subjectStorage;
762 const QStringView subject;
763
764 const QRegularExpression::MatchType matchType;
765 const QRegularExpression::MatchOptions matchOptions;
766
767 // the capturedOffsets vector contains pairs of (start, end) positions
768 // for each captured substring
769 QList<qsizetype> capturedOffsets;
770
771 int capturedCount = 0;
772
773 bool hasMatch = false;
774 bool hasPartialMatch = false;
775 bool isValid = false;
776};
777
778struct QRegularExpressionMatchIteratorPrivate : QSharedData
779{
780 QRegularExpressionMatchIteratorPrivate(const QRegularExpression &re,
781 QRegularExpression::MatchType matchType,
782 QRegularExpression::MatchOptions matchOptions,
783 const QRegularExpressionMatch &next);
784
785 bool hasNext() const;
786 QRegularExpressionMatch next;
787 const QRegularExpression regularExpression;
788 const QRegularExpression::MatchType matchType;
789 const QRegularExpression::MatchOptions matchOptions;
790};
791
792/*!
793 \internal
794
795 Used to centralize the warning about using an invalid QRegularExpression.
796 In case the pattern is an illegal UTF-16 string, we can't pass print it
797 (pass it to qUtf16Printable, etc.), so we need to check for that.
798*/
799Q_DECL_COLD_FUNCTION
800void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *where)
801{
802 if (pattern.isValidUtf16()) {
803 qWarning(msg: "%s(): called on an invalid QRegularExpression object "
804 "(pattern is '%ls')", where, qUtf16Printable(pattern));
805 } else {
806 qWarning(msg: "%s(): called on an invalid QRegularExpression object", where);
807 }
808}
809
810/*!
811 \internal
812*/
813QRegularExpression::QRegularExpression(QRegularExpressionPrivate &dd)
814 : d(&dd)
815{
816}
817
818/*!
819 \internal
820*/
821QRegularExpressionPrivate::QRegularExpressionPrivate()
822 : QSharedData(),
823 patternOptions(),
824 pattern(),
825 mutex(),
826 compiledPattern(nullptr),
827 errorCode(0),
828 errorOffset(-1),
829 capturingCount(0),
830 usingCrLfNewlines(false),
831 isDirty(true)
832{
833}
834
835/*!
836 \internal
837*/
838QRegularExpressionPrivate::~QRegularExpressionPrivate()
839{
840 cleanCompiledPattern();
841}
842
843/*!
844 \internal
845
846 Copies the private, which means copying only the pattern and the pattern
847 options. The compiledPattern pointer is NOT copied (we
848 do not own it any more), and in general all the members set when
849 compiling a pattern are set to default values. isDirty is set back to true
850 so that the pattern has to be recompiled again.
851*/
852QRegularExpressionPrivate::QRegularExpressionPrivate(const QRegularExpressionPrivate &other)
853 : QSharedData(other),
854 patternOptions(other.patternOptions),
855 pattern(other.pattern),
856 mutex(),
857 compiledPattern(nullptr),
858 errorCode(0),
859 errorOffset(-1),
860 capturingCount(0),
861 usingCrLfNewlines(false),
862 isDirty(true)
863{
864}
865
866/*!
867 \internal
868*/
869void QRegularExpressionPrivate::cleanCompiledPattern()
870{
871 pcre2_code_free_16(compiledPattern);
872 compiledPattern = nullptr;
873 errorCode = 0;
874 errorOffset = -1;
875 capturingCount = 0;
876 usingCrLfNewlines = false;
877}
878
879/*!
880 \internal
881*/
882void QRegularExpressionPrivate::compilePattern()
883{
884 const QMutexLocker lock(&mutex);
885
886 if (!isDirty)
887 return;
888
889 isDirty = false;
890 cleanCompiledPattern();
891
892 int options = convertToPcreOptions(patternOptions);
893 options |= PCRE2_UTF;
894
895 PCRE2_SIZE patternErrorOffset;
896 compiledPattern = pcre2_compile_16(reinterpret_cast<PCRE2_SPTR16>(pattern.constData()),
897 pattern.size(),
898 options,
899 &errorCode,
900 &patternErrorOffset,
901 nullptr);
902
903 if (!compiledPattern) {
904 errorOffset = qsizetype(patternErrorOffset);
905 return;
906 } else {
907 // ignore whatever PCRE2 wrote into errorCode -- leave it to 0 to mean "no error"
908 errorCode = 0;
909 }
910
911 optimizePattern();
912 getPatternInfo();
913}
914
915/*!
916 \internal
917*/
918void QRegularExpressionPrivate::getPatternInfo()
919{
920 Q_ASSERT(compiledPattern);
921
922 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_CAPTURECOUNT, &capturingCount);
923
924 // detect the settings for the newline
925 unsigned int patternNewlineSetting;
926 if (pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NEWLINE, &patternNewlineSetting) != 0) {
927 // no option was specified in the regexp, grab PCRE build defaults
928 pcre2_config_16(PCRE2_CONFIG_NEWLINE, &patternNewlineSetting);
929 }
930
931 usingCrLfNewlines = (patternNewlineSetting == PCRE2_NEWLINE_CRLF) ||
932 (patternNewlineSetting == PCRE2_NEWLINE_ANY) ||
933 (patternNewlineSetting == PCRE2_NEWLINE_ANYCRLF);
934
935 unsigned int hasJOptionChanged;
936 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_JCHANGED, &hasJOptionChanged);
937 if (Q_UNLIKELY(hasJOptionChanged)) {
938 qWarning(msg: "QRegularExpressionPrivate::getPatternInfo(): the pattern '%ls'\n is using the (?J) option; duplicate capturing group names are not supported by Qt",
939 qUtf16Printable(pattern));
940 }
941}
942
943
944/*
945 Simple "smartpointer" wrapper around a pcre2_jit_stack_16, to be used with
946 QThreadStorage.
947*/
948namespace {
949struct PcreJitStackFree
950{
951 void operator()(pcre2_jit_stack_16 *stack)
952 {
953 if (stack)
954 pcre2_jit_stack_free_16(stack);
955 }
956};
957Q_CONSTINIT static thread_local std::unique_ptr<pcre2_jit_stack_16, PcreJitStackFree> jitStacks;
958}
959
960/*!
961 \internal
962*/
963static pcre2_jit_stack_16 *qtPcreCallback(void *)
964{
965 return jitStacks.get();
966}
967
968/*!
969 \internal
970*/
971static bool isJitEnabled()
972{
973 QByteArray jitEnvironment = qgetenv(varName: "QT_ENABLE_REGEXP_JIT");
974 if (!jitEnvironment.isEmpty()) {
975 bool ok;
976 int enableJit = jitEnvironment.toInt(ok: &ok);
977 return ok ? (enableJit != 0) : true;
978 }
979
980#ifdef QT_DEBUG
981 return false;
982#elif defined(Q_OS_MACOS)
983 return !qt_mac_runningUnderRosetta();
984#else
985 return true;
986#endif
987}
988
989/*!
990 \internal
991
992 The purpose of the function is to call pcre2_jit_compile_16, which
993 JIT-compiles the pattern.
994
995 It gets called when a pattern is recompiled by us (in compilePattern()),
996 under mutex protection.
997*/
998void QRegularExpressionPrivate::optimizePattern()
999{
1000 Q_ASSERT(compiledPattern);
1001
1002 static const bool enableJit = isJitEnabled();
1003
1004 if (!enableJit)
1005 return;
1006
1007 pcre2_jit_compile_16(compiledPattern, PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_PARTIAL_HARD);
1008}
1009
1010/*!
1011 \internal
1012
1013 Returns the capturing group number for the given name. Duplicated names for
1014 capturing groups are not supported.
1015*/
1016int QRegularExpressionPrivate::captureIndexForName(QStringView name) const
1017{
1018 Q_ASSERT(!name.isEmpty());
1019
1020 if (!compiledPattern)
1021 return -1;
1022
1023 // See the other usages of pcre2_pattern_info_16 for more details about this
1024 PCRE2_SPTR16 *namedCapturingTable;
1025 unsigned int namedCapturingTableEntryCount;
1026 unsigned int namedCapturingTableEntrySize;
1027
1028 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
1029 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
1030 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
1031
1032 for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
1033 const auto currentNamedCapturingTableRow =
1034 reinterpret_cast<const char16_t *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
1035
1036 if (name == (currentNamedCapturingTableRow + 1)) {
1037 const int index = *currentNamedCapturingTableRow;
1038 return index;
1039 }
1040 }
1041
1042 return -1;
1043}
1044
1045/*!
1046 \internal
1047
1048 This is a simple wrapper for pcre2_match_16 for handling the case in which the
1049 JIT runs out of memory. In that case, we allocate a thread-local JIT stack
1050 and re-run pcre2_match_16.
1051*/
1052static int safe_pcre2_match_16(const pcre2_code_16 *code,
1053 PCRE2_SPTR16 subject, qsizetype length,
1054 qsizetype startOffset, int options,
1055 pcre2_match_data_16 *matchData,
1056 pcre2_match_context_16 *matchContext)
1057{
1058 int result = pcre2_match_16(code, subject, length,
1059 startOffset, options, matchData, matchContext);
1060
1061 if (result == PCRE2_ERROR_JIT_STACKLIMIT && !jitStacks) {
1062 // The default JIT stack size in PCRE is 32K,
1063 // we allocate from 32K up to 512K.
1064 jitStacks.reset(p: pcre2_jit_stack_create_16(32 * 1024, 512 * 1024, NULL));
1065
1066 result = pcre2_match_16(code, subject, length,
1067 startOffset, options, matchData, matchContext);
1068 }
1069
1070 return result;
1071}
1072
1073/*!
1074 \internal
1075
1076 Performs a match on the subject string view held by \a priv. The
1077 match will be of type priv->matchType and using the options
1078 priv->matchOptions; the matching \a offset is relative the
1079 substring, and if negative, it's taken as an offset from the end of
1080 the substring.
1081
1082 It also advances a match if a previous result is given as \a
1083 previous. The subject string goes a Unicode validity check if
1084 \a checkSubjectString is CheckSubjectString and the match options don't
1085 include DontCheckSubjectStringMatchOption (PCRE doesn't like illegal
1086 UTF-16 sequences).
1087
1088 \a priv is modified to hold the results of the match.
1089
1090 Advancing a match is a tricky algorithm. If the previous match matched a
1091 non-empty string, we just do an ordinary match at the offset position.
1092
1093 If the previous match matched an empty string, then an anchored, non-empty
1094 match is attempted at the offset position. If that succeeds, then we got
1095 the next match and we can return it. Otherwise, we advance by 1 position
1096 (which can be one or two code units in UTF-16!) and reattempt a "normal"
1097 match. We also have the problem of detecting the current newline format: if
1098 the new advanced offset is pointing to the beginning of a CRLF sequence, we
1099 must advance over it.
1100*/
1101void QRegularExpressionPrivate::doMatch(QRegularExpressionMatchPrivate *priv,
1102 qsizetype offset,
1103 CheckSubjectStringOption checkSubjectStringOption,
1104 const QRegularExpressionMatchPrivate *previous) const
1105{
1106 Q_ASSERT(priv);
1107 Q_ASSUME(priv != previous);
1108
1109 const qsizetype subjectLength = priv->subject.size();
1110
1111 if (offset < 0)
1112 offset += subjectLength;
1113
1114 if (offset < 0 || offset > subjectLength)
1115 return;
1116
1117 if (Q_UNLIKELY(!compiledPattern)) {
1118 qtWarnAboutInvalidRegularExpression(pattern, where: "QRegularExpressionPrivate::doMatch");
1119 return;
1120 }
1121
1122 // skip doing the actual matching if NoMatch type was requested
1123 if (priv->matchType == QRegularExpression::NoMatch) {
1124 priv->isValid = true;
1125 return;
1126 }
1127
1128 int pcreOptions = convertToPcreOptions(matchOptions: priv->matchOptions);
1129
1130 if (priv->matchType == QRegularExpression::PartialPreferCompleteMatch)
1131 pcreOptions |= PCRE2_PARTIAL_SOFT;
1132 else if (priv->matchType == QRegularExpression::PartialPreferFirstMatch)
1133 pcreOptions |= PCRE2_PARTIAL_HARD;
1134
1135 if (checkSubjectStringOption == DontCheckSubjectString)
1136 pcreOptions |= PCRE2_NO_UTF_CHECK;
1137
1138 bool previousMatchWasEmpty = false;
1139 if (previous && previous->hasMatch &&
1140 (previous->capturedOffsets.at(i: 0) == previous->capturedOffsets.at(i: 1))) {
1141 previousMatchWasEmpty = true;
1142 }
1143
1144 pcre2_match_context_16 *matchContext = pcre2_match_context_create_16(nullptr);
1145 pcre2_jit_stack_assign_16(matchContext, &qtPcreCallback, nullptr);
1146 pcre2_match_data_16 *matchData = pcre2_match_data_create_from_pattern_16(compiledPattern, nullptr);
1147
1148 // PCRE does not accept a null pointer as subject string, even if
1149 // its length is zero. We however allow it in input: a QStringView
1150 // subject may have data == nullptr. In this case, to keep PCRE
1151 // happy, pass a pointer to a dummy character.
1152 const char16_t dummySubject = 0;
1153 const char16_t * const subjectUtf16 = [&]()
1154 {
1155 const auto subjectUtf16 = priv->subject.utf16();
1156 if (subjectUtf16)
1157 return subjectUtf16;
1158 Q_ASSERT(subjectLength == 0);
1159 return &dummySubject;
1160 }();
1161
1162 int result;
1163
1164 if (!previousMatchWasEmpty) {
1165 result = safe_pcre2_match_16(code: compiledPattern,
1166 subject: reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), length: subjectLength,
1167 startOffset: offset, options: pcreOptions,
1168 matchData, matchContext);
1169 } else {
1170 result = safe_pcre2_match_16(code: compiledPattern,
1171 subject: reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), length: subjectLength,
1172 startOffset: offset, options: pcreOptions | PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED,
1173 matchData, matchContext);
1174
1175 if (result == PCRE2_ERROR_NOMATCH) {
1176 ++offset;
1177
1178 if (usingCrLfNewlines
1179 && offset < subjectLength
1180 && subjectUtf16[offset - 1] == u'\r'
1181 && subjectUtf16[offset] == u'\n') {
1182 ++offset;
1183 } else if (offset < subjectLength
1184 && QChar::isLowSurrogate(ucs4: subjectUtf16[offset])) {
1185 ++offset;
1186 }
1187
1188 result = safe_pcre2_match_16(code: compiledPattern,
1189 subject: reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), length: subjectLength,
1190 startOffset: offset, options: pcreOptions,
1191 matchData, matchContext);
1192 }
1193 }
1194
1195#ifdef QREGULAREXPRESSION_DEBUG
1196 qDebug() << "Matching" << pattern << "against" << subject
1197 << "offset" << offset
1198 << priv->matchType << priv->matchOptions << previousMatchWasEmpty
1199 << "result" << result;
1200#endif
1201
1202 // result == 0 means not enough space in captureOffsets; should never happen
1203 Q_ASSERT(result != 0);
1204
1205 if (result > 0) {
1206 // full match
1207 priv->isValid = true;
1208 priv->hasMatch = true;
1209 priv->capturedCount = result;
1210 priv->capturedOffsets.resize(size: result * 2);
1211 } else {
1212 // no match, partial match or error
1213 priv->hasPartialMatch = (result == PCRE2_ERROR_PARTIAL);
1214 priv->isValid = (result == PCRE2_ERROR_NOMATCH || result == PCRE2_ERROR_PARTIAL);
1215
1216 if (result == PCRE2_ERROR_PARTIAL) {
1217 // partial match:
1218 // leave the start and end capture offsets (i.e. cap(0))
1219 priv->capturedCount = 1;
1220 priv->capturedOffsets.resize(size: 2);
1221 } else {
1222 // no match or error
1223 priv->capturedCount = 0;
1224 priv->capturedOffsets.clear();
1225 }
1226 }
1227
1228 // copy the captured substrings offsets, if any
1229 if (priv->capturedCount) {
1230 PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_16(matchData);
1231 qsizetype *const capturedOffsets = priv->capturedOffsets.data();
1232
1233 // We rely on the fact that capturing groups that did not
1234 // capture anything have offset -1, but PCRE technically
1235 // returns "PCRE2_UNSET". Test that out, better safe than
1236 // sorry...
1237 static_assert(qsizetype(PCRE2_UNSET) == qsizetype(-1), "Internal error: PCRE2 changed its API");
1238
1239 for (int i = 0; i < priv->capturedCount * 2; ++i)
1240 capturedOffsets[i] = qsizetype(ovector[i]);
1241
1242 // For partial matches, PCRE2 and PCRE1 differ in behavior when lookbehinds
1243 // are involved. PCRE2 reports the real begin of the match and the maximum
1244 // used lookbehind as distinct information; PCRE1 instead automatically
1245 // adjusted ovector[0] to include the maximum lookbehind.
1246 //
1247 // For instance, given the pattern "\bstring\b", and the subject "a str":
1248 // * PCRE1 reports partial, capturing " str"
1249 // * PCRE2 reports partial, capturing "str" with a lookbehind of 1
1250 //
1251 // To keep behavior, emulate PCRE1 here.
1252 // (Eventually, we could expose the lookbehind info in a future patch.)
1253 if (result == PCRE2_ERROR_PARTIAL) {
1254 unsigned int maximumLookBehind;
1255 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_MAXLOOKBEHIND, &maximumLookBehind);
1256 capturedOffsets[0] -= maximumLookBehind;
1257 }
1258 }
1259
1260 pcre2_match_data_free_16(matchData);
1261 pcre2_match_context_free_16(matchContext);
1262}
1263
1264/*!
1265 \internal
1266*/
1267QRegularExpressionMatchPrivate::QRegularExpressionMatchPrivate(const QRegularExpression &re,
1268 const QString &subjectStorage,
1269 QStringView subject,
1270 QRegularExpression::MatchType matchType,
1271 QRegularExpression::MatchOptions matchOptions)
1272 : regularExpression(re),
1273 subjectStorage(subjectStorage),
1274 subject(subject),
1275 matchType(matchType),
1276 matchOptions(matchOptions)
1277{
1278}
1279
1280/*!
1281 \internal
1282*/
1283QRegularExpressionMatch QRegularExpressionMatchPrivate::nextMatch() const
1284{
1285 Q_ASSERT(isValid);
1286 Q_ASSERT(hasMatch || hasPartialMatch);
1287
1288 auto nextPrivate = new QRegularExpressionMatchPrivate(regularExpression,
1289 subjectStorage,
1290 subject,
1291 matchType,
1292 matchOptions);
1293
1294 // Note the DontCheckSubjectString passed for the check of the subject string:
1295 // if we're advancing a match on the same subject,
1296 // then that subject was already checked at least once (when this object
1297 // was created, or when the object that created this one was created, etc.)
1298 regularExpression.d->doMatch(priv: nextPrivate,
1299 offset: capturedOffsets.at(i: 1),
1300 checkSubjectStringOption: QRegularExpressionPrivate::DontCheckSubjectString,
1301 previous: this);
1302 return QRegularExpressionMatch(*nextPrivate);
1303}
1304
1305/*!
1306 \internal
1307*/
1308QRegularExpressionMatchIteratorPrivate::QRegularExpressionMatchIteratorPrivate(const QRegularExpression &re,
1309 QRegularExpression::MatchType matchType,
1310 QRegularExpression::MatchOptions matchOptions,
1311 const QRegularExpressionMatch &next)
1312 : next(next),
1313 regularExpression(re),
1314 matchType(matchType), matchOptions(matchOptions)
1315{
1316}
1317
1318/*!
1319 \internal
1320*/
1321bool QRegularExpressionMatchIteratorPrivate::hasNext() const
1322{
1323 return next.isValid() && (next.hasMatch() || next.hasPartialMatch());
1324}
1325
1326// PUBLIC API
1327
1328/*!
1329 Constructs a QRegularExpression object with an empty pattern and no pattern
1330 options.
1331
1332 \sa setPattern(), setPatternOptions()
1333*/
1334QRegularExpression::QRegularExpression()
1335 : d(new QRegularExpressionPrivate)
1336{
1337}
1338
1339/*!
1340 Constructs a QRegularExpression object using the given \a pattern as
1341 pattern and the \a options as the pattern options.
1342
1343 \sa setPattern(), setPatternOptions()
1344*/
1345QRegularExpression::QRegularExpression(const QString &pattern, PatternOptions options)
1346 : d(new QRegularExpressionPrivate)
1347{
1348 d->pattern = pattern;
1349 d->patternOptions = options;
1350}
1351
1352/*!
1353 Constructs a QRegularExpression object as a copy of \a re.
1354
1355 \sa operator=()
1356*/
1357QRegularExpression::QRegularExpression(const QRegularExpression &re) noexcept = default;
1358
1359/*!
1360 \fn QRegularExpression::QRegularExpression(QRegularExpression &&re)
1361
1362 \since 6.1
1363
1364 Constructs a QRegularExpression object by moving from \a re.
1365
1366 Note that a moved-from QRegularExpression can only be destroyed or
1367 assigned to. The effect of calling other functions than the destructor
1368 or one of the assignment operators is undefined.
1369
1370 \sa operator=()
1371*/
1372
1373/*!
1374 Destroys the QRegularExpression object.
1375*/
1376QRegularExpression::~QRegularExpression()
1377{
1378}
1379
1380QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QRegularExpressionPrivate)
1381
1382/*!
1383 Assigns the regular expression \a re to this object, and returns a reference
1384 to the copy. Both the pattern and the pattern options are copied.
1385*/
1386QRegularExpression &QRegularExpression::operator=(const QRegularExpression &re) noexcept = default;
1387
1388/*!
1389 \fn void QRegularExpression::swap(QRegularExpression &other)
1390
1391 Swaps the regular expression \a other with this regular expression. This
1392 operation is very fast and never fails.
1393*/
1394
1395/*!
1396 Returns the pattern string of the regular expression.
1397
1398 \sa setPattern(), patternOptions()
1399*/
1400QString QRegularExpression::pattern() const
1401{
1402 return d->pattern;
1403}
1404
1405/*!
1406 Sets the pattern string of the regular expression to \a pattern. The
1407 pattern options are left unchanged.
1408
1409 \sa pattern(), setPatternOptions()
1410*/
1411void QRegularExpression::setPattern(const QString &pattern)
1412{
1413 if (d->pattern == pattern)
1414 return;
1415 d.detach();
1416 d->isDirty = true;
1417 d->pattern = pattern;
1418}
1419
1420/*!
1421 Returns the pattern options for the regular expression.
1422
1423 \sa setPatternOptions(), pattern()
1424*/
1425QRegularExpression::PatternOptions QRegularExpression::patternOptions() const
1426{
1427 return d->patternOptions;
1428}
1429
1430/*!
1431 Sets the given \a options as the pattern options of the regular expression.
1432 The pattern string is left unchanged.
1433
1434 \sa patternOptions(), setPattern()
1435*/
1436void QRegularExpression::setPatternOptions(PatternOptions options)
1437{
1438 if (d->patternOptions == options)
1439 return;
1440 d.detach();
1441 d->isDirty = true;
1442 d->patternOptions = options;
1443}
1444
1445/*!
1446 Returns the number of capturing groups inside the pattern string,
1447 or -1 if the regular expression is not valid.
1448
1449 \note The implicit capturing group 0 is \e{not} included in the returned number.
1450
1451 \sa isValid()
1452*/
1453int QRegularExpression::captureCount() const
1454{
1455 if (!isValid()) // will compile the pattern
1456 return -1;
1457 return d->capturingCount;
1458}
1459
1460/*!
1461 \since 5.1
1462
1463 Returns a list of captureCount() + 1 elements, containing the names of the
1464 named capturing groups in the pattern string. The list is sorted such that
1465 the element of the list at position \c{i} is the name of the \c{i}-th
1466 capturing group, if it has a name, or an empty string if that capturing
1467 group is unnamed.
1468
1469 For instance, given the regular expression
1470
1471 \snippet code/src_corelib_text_qregularexpression.cpp 32
1472
1473 namedCaptureGroups() will return the following list:
1474
1475 \snippet code/src_corelib_text_qregularexpression.cpp 33
1476
1477 which corresponds to the fact that the capturing group #0 (corresponding to
1478 the whole match) has no name, the capturing group #1 has name "day", the
1479 capturing group #2 has name "month", etc.
1480
1481 If the regular expression is not valid, returns an empty list.
1482
1483 \sa isValid(), QRegularExpressionMatch::captured(), QString::isEmpty()
1484*/
1485QStringList QRegularExpression::namedCaptureGroups() const
1486{
1487 if (!isValid()) // isValid() will compile the pattern
1488 return QStringList();
1489
1490 // namedCapturingTable will point to a table of
1491 // namedCapturingTableEntryCount entries, each one of which
1492 // contains one ushort followed by the name, NUL terminated.
1493 // The ushort is the numerical index of the name in the pattern.
1494 // The length of each entry is namedCapturingTableEntrySize.
1495 PCRE2_SPTR16 *namedCapturingTable;
1496 unsigned int namedCapturingTableEntryCount;
1497 unsigned int namedCapturingTableEntrySize;
1498
1499 pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
1500 pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
1501 pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
1502
1503 // The +1 is for the implicit group #0
1504 QStringList result(d->capturingCount + 1);
1505
1506 for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
1507 const auto currentNamedCapturingTableRow =
1508 reinterpret_cast<const char16_t *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
1509
1510 const int index = *currentNamedCapturingTableRow;
1511 result[index] = QString::fromUtf16(currentNamedCapturingTableRow + 1);
1512 }
1513
1514 return result;
1515}
1516
1517/*!
1518 Returns \c true if the regular expression is a valid regular expression (that
1519 is, it contains no syntax errors, etc.), or false otherwise. Use
1520 errorString() to obtain a textual description of the error.
1521
1522 \sa errorString(), patternErrorOffset()
1523*/
1524bool QRegularExpression::isValid() const
1525{
1526 d.data()->compilePattern();
1527 return d->compiledPattern;
1528}
1529
1530/*!
1531 Returns a textual description of the error found when checking the validity
1532 of the regular expression, or "no error" if no error was found.
1533
1534 \sa isValid(), patternErrorOffset()
1535*/
1536QString QRegularExpression::errorString() const
1537{
1538 d.data()->compilePattern();
1539 if (d->errorCode) {
1540 QString errorString;
1541 int errorStringLength;
1542 do {
1543 errorString.resize(size: errorString.size() + 64);
1544 errorStringLength = pcre2_get_error_message_16(d->errorCode,
1545 reinterpret_cast<ushort *>(errorString.data()),
1546 errorString.size());
1547 } while (errorStringLength < 0);
1548 errorString.resize(size: errorStringLength);
1549
1550#ifdef QT_NO_TRANSLATION
1551 return errorString;
1552#else
1553 return QCoreApplication::translate(context: "QRegularExpression", key: std::move(errorString).toLatin1().constData());
1554#endif
1555 }
1556#ifdef QT_NO_TRANSLATION
1557 return u"no error"_s;
1558#else
1559 return QCoreApplication::translate(context: "QRegularExpression", key: "no error");
1560#endif
1561}
1562
1563/*!
1564 Returns the offset, inside the pattern string, at which an error was found
1565 when checking the validity of the regular expression. If no error was
1566 found, then -1 is returned.
1567
1568 \sa pattern(), isValid(), errorString()
1569*/
1570qsizetype QRegularExpression::patternErrorOffset() const
1571{
1572 d.data()->compilePattern();
1573 return d->errorOffset;
1574}
1575
1576/*!
1577 Attempts to match the regular expression against the given \a subject
1578 string, starting at the position \a offset inside the subject, using a
1579 match of type \a matchType and honoring the given \a matchOptions.
1580
1581 The returned QRegularExpressionMatch object contains the results of the
1582 match.
1583
1584 \sa QRegularExpressionMatch, {normal matching}
1585*/
1586QRegularExpressionMatch QRegularExpression::match(const QString &subject,
1587 qsizetype offset,
1588 MatchType matchType,
1589 MatchOptions matchOptions) const
1590{
1591 d.data()->compilePattern();
1592 auto priv = new QRegularExpressionMatchPrivate(*this,
1593 subject,
1594 QStringView(subject),
1595 matchType,
1596 matchOptions);
1597 d->doMatch(priv, offset);
1598 return QRegularExpressionMatch(*priv);
1599}
1600
1601#if QT_DEPRECATED_SINCE(6, 8)
1602/*!
1603 \since 6.0
1604 \overload
1605 \obsolete
1606
1607 Use matchView() instead.
1608*/
1609QRegularExpressionMatch QRegularExpression::match(QStringView subjectView,
1610 qsizetype offset,
1611 MatchType matchType,
1612 MatchOptions matchOptions) const
1613{
1614 return matchView(subjectView, offset, matchType, matchOptions);
1615}
1616#endif // QT_DEPRECATED_SINCE(6, 8)
1617
1618/*!
1619 \since 6.5
1620 \overload
1621
1622 Attempts to match the regular expression against the given \a subjectView
1623 string view, starting at the position \a offset inside the subject, using a
1624 match of type \a matchType and honoring the given \a matchOptions.
1625
1626 The returned QRegularExpressionMatch object contains the results of the
1627 match.
1628
1629 \note The data referenced by \a subjectView must remain valid as long
1630 as there are QRegularExpressionMatch objects using it.
1631
1632 \sa QRegularExpressionMatch, {normal matching}
1633*/
1634QRegularExpressionMatch QRegularExpression::matchView(QStringView subjectView,
1635 qsizetype offset,
1636 MatchType matchType,
1637 MatchOptions matchOptions) const
1638{
1639 d.data()->compilePattern();
1640 auto priv = new QRegularExpressionMatchPrivate(*this,
1641 QString(),
1642 subjectView,
1643 matchType,
1644 matchOptions);
1645 d->doMatch(priv, offset);
1646 return QRegularExpressionMatch(*priv);
1647}
1648
1649/*!
1650 Attempts to perform a global match of the regular expression against the
1651 given \a subject string, starting at the position \a offset inside the
1652 subject, using a match of type \a matchType and honoring the given \a
1653 matchOptions.
1654
1655 The returned QRegularExpressionMatchIterator is positioned before the
1656 first match result (if any).
1657
1658 \sa QRegularExpressionMatchIterator, {global matching}
1659*/
1660QRegularExpressionMatchIterator QRegularExpression::globalMatch(const QString &subject,
1661 qsizetype offset,
1662 MatchType matchType,
1663 MatchOptions matchOptions) const
1664{
1665 QRegularExpressionMatchIteratorPrivate *priv =
1666 new QRegularExpressionMatchIteratorPrivate(*this,
1667 matchType,
1668 matchOptions,
1669 match(subject, offset, matchType, matchOptions));
1670
1671 return QRegularExpressionMatchIterator(*priv);
1672}
1673
1674#if QT_DEPRECATED_SINCE(6, 8)
1675/*!
1676 \since 6.0
1677 \overload
1678 \obsolete
1679
1680 Use globalMatchView() instead.
1681*/
1682QRegularExpressionMatchIterator QRegularExpression::globalMatch(QStringView subjectView,
1683 qsizetype offset,
1684 MatchType matchType,
1685 MatchOptions matchOptions) const
1686{
1687 return globalMatchView(subjectView, offset, matchType, matchOptions);
1688}
1689#endif // QT_DEPRECATED_SINCE(6, 8)
1690
1691/*!
1692 \since 6.5
1693 \overload
1694
1695 Attempts to perform a global match of the regular expression against the
1696 given \a subjectView string view, starting at the position \a offset inside the
1697 subject, using a match of type \a matchType and honoring the given \a
1698 matchOptions.
1699
1700 The returned QRegularExpressionMatchIterator is positioned before the
1701 first match result (if any).
1702
1703 \note The data referenced by \a subjectView must remain valid as
1704 long as there are QRegularExpressionMatchIterator or
1705 QRegularExpressionMatch objects using it.
1706
1707 \sa QRegularExpressionMatchIterator, {global matching}
1708*/
1709QRegularExpressionMatchIterator QRegularExpression::globalMatchView(QStringView subjectView,
1710 qsizetype offset,
1711 MatchType matchType,
1712 MatchOptions matchOptions) const
1713{
1714 QRegularExpressionMatchIteratorPrivate *priv =
1715 new QRegularExpressionMatchIteratorPrivate(*this,
1716 matchType,
1717 matchOptions,
1718 matchView(subjectView, offset, matchType, matchOptions));
1719
1720 return QRegularExpressionMatchIterator(*priv);
1721}
1722
1723/*!
1724 \since 5.4
1725
1726 Compiles the pattern immediately, including JIT compiling it (if
1727 the JIT is enabled) for optimization.
1728
1729 \sa isValid(), {Debugging Code that Uses QRegularExpression}
1730*/
1731void QRegularExpression::optimize() const
1732{
1733 d.data()->compilePattern();
1734}
1735
1736/*!
1737 Returns \c true if the regular expression is equal to \a re, or false
1738 otherwise. Two QRegularExpression objects are equal if they have
1739 the same pattern string and the same pattern options.
1740
1741 \sa operator!=()
1742*/
1743bool QRegularExpression::operator==(const QRegularExpression &re) const
1744{
1745 return (d == re.d) ||
1746 (d->pattern == re.d->pattern && d->patternOptions == re.d->patternOptions);
1747}
1748
1749/*!
1750 \fn QRegularExpression & QRegularExpression::operator=(QRegularExpression && re)
1751
1752 Move-assigns the regular expression \a re to this object, and returns a
1753 reference to the result. Both the pattern and the pattern options are copied.
1754
1755 Note that a moved-from QRegularExpression can only be destroyed or
1756 assigned to. The effect of calling other functions than the destructor
1757 or one of the assignment operators is undefined.
1758*/
1759
1760/*!
1761 \fn bool QRegularExpression::operator!=(const QRegularExpression &re) const
1762
1763 Returns \c true if the regular expression is different from \a re, or
1764 false otherwise.
1765
1766 \sa operator==()
1767*/
1768
1769/*!
1770 \since 5.6
1771 \relates QRegularExpression
1772
1773 Returns the hash value for \a key, using
1774 \a seed to seed the calculation.
1775*/
1776size_t qHash(const QRegularExpression &key, size_t seed) noexcept
1777{
1778 return qHashMulti(seed, args: key.d->pattern, args: key.d->patternOptions);
1779}
1780
1781/*!
1782 \fn QString QRegularExpression::escape(const QString &str)
1783 \overload
1784*/
1785
1786/*!
1787 \since 5.15
1788
1789 Escapes all characters of \a str so that they no longer have any special
1790 meaning when used as a regular expression pattern string, and returns
1791 the escaped string. For instance:
1792
1793 \snippet code/src_corelib_text_qregularexpression.cpp 26
1794
1795 This is very convenient in order to build patterns from arbitrary strings:
1796
1797 \snippet code/src_corelib_text_qregularexpression.cpp 27
1798
1799 \note This function implements Perl's quotemeta algorithm and escapes with
1800 a backslash all characters in \a str, except for the characters in the
1801 \c{[A-Z]}, \c{[a-z]} and \c{[0-9]} ranges, as well as the underscore
1802 (\c{_}) character. The only difference with Perl is that a literal NUL
1803 inside \a str is escaped with the sequence \c{"\\0"} (backslash +
1804 \c{'0'}), instead of \c{"\\\0"} (backslash + \c{NUL}).
1805*/
1806QString QRegularExpression::escape(QStringView str)
1807{
1808 QString result;
1809 const qsizetype count = str.size();
1810 result.reserve(asize: count * 2);
1811
1812 // everything but [a-zA-Z0-9_] gets escaped,
1813 // cf. perldoc -f quotemeta
1814 for (qsizetype i = 0; i < count; ++i) {
1815 const QChar current = str.at(n: i);
1816
1817 if (current == QChar::Null) {
1818 // unlike Perl, a literal NUL must be escaped with
1819 // "\\0" (backslash + 0) and not "\\\0" (backslash + NUL),
1820 // because pcre16_compile uses a NUL-terminated string
1821 result.append(c: u'\\');
1822 result.append(c: u'0');
1823 } else if ((current < u'a' || current > u'z') &&
1824 (current < u'A' || current > u'Z') &&
1825 (current < u'0' || current > u'9') &&
1826 current != u'_') {
1827 result.append(c: u'\\');
1828 result.append(c: current);
1829 if (current.isHighSurrogate() && i < (count - 1))
1830 result.append(c: str.at(n: ++i));
1831 } else {
1832 result.append(c: current);
1833 }
1834 }
1835
1836 result.squeeze();
1837 return result;
1838}
1839
1840/*!
1841 \since 5.12
1842 \fn QString QRegularExpression::wildcardToRegularExpression(const QString &pattern, WildcardConversionOptions options)
1843 \overload
1844*/
1845
1846/*!
1847 \since 6.0
1848 \enum QRegularExpression::WildcardConversionOption
1849
1850 The WildcardConversionOption enum defines modifiers to the way a wildcard glob
1851 pattern gets converted to a regular expression pattern.
1852
1853 \value DefaultWildcardConversion
1854 No conversion options are set.
1855
1856 \value UnanchoredWildcardConversion
1857 The conversion will not anchor the pattern. This allows for partial string matches of
1858 wildcard expressions.
1859
1860 \value [since 6.6] NonPathWildcardConversion
1861 The conversion will \e{not} interpret the pattern as filepath globbing.
1862
1863 \sa QRegularExpression::wildcardToRegularExpression
1864*/
1865
1866/*!
1867 \since 5.15
1868
1869 Returns a regular expression representation of the given glob \a pattern.
1870
1871 There are two transformations possible, one that targets file path
1872 globbing, and another one which is more generic.
1873
1874 By default, the transformation is targeting file path globbing,
1875 which means in particular that path separators receive special
1876 treatment. This implies that it is not just a basic translation
1877 from "*" to ".*" and similar.
1878
1879 \snippet code/src_corelib_text_qregularexpression.cpp 31
1880
1881 The more generic globbing transformation is available by passing
1882 \c NonPathWildcardConversion in the conversion \a options.
1883
1884 This implementation follows closely the definition
1885 of wildcard for glob patterns:
1886 \table
1887 \row \li \b{c}
1888 \li Any character represents itself apart from those mentioned
1889 below. Thus \b{c} matches the character \e c.
1890 \row \li \b{?}
1891 \li Matches any single character, except for a path separator
1892 (in case file path globbing has been selected). It is the
1893 same as b{.} in full regexps.
1894 \row \li \b{*}
1895 \li Matches zero or more of any characters, except for path
1896 separators (in case file path globbing has been selected). It is the
1897 same as \b{.*} in full regexps.
1898 \row \li \b{[abc]}
1899 \li Matches one character given in the bracket.
1900 \row \li \b{[a-c]}
1901 \li Matches one character from the range given in the bracket.
1902 \row \li \b{[!abc]}
1903 \li Matches one character that is not given in the bracket. It is the
1904 same as \b{[^abc]} in full regexp.
1905 \row \li \b{[!a-c]}
1906 \li Matches one character that is not from the range given in the
1907 bracket. It is the same as \b{[^a-c]} in full regexp.
1908 \endtable
1909
1910 \note For historical reasons, a backslash (\\) character is \e not
1911 an escape char in this context. In order to match one of the
1912 special characters, place it in square brackets (for example,
1913 \c{[?]}).
1914
1915 More information about the implementation can be found in:
1916 \list
1917 \li \l {https://en.wikipedia.org/wiki/Glob_(programming)} {The Wikipedia Glob article}
1918 \li \c {man 7 glob}
1919 \endlist
1920
1921 By default, the returned regular expression is fully anchored. In other
1922 words, there is no need of calling anchoredPattern() again on the
1923 result. To get a regular expression that is not anchored, pass
1924 UnanchoredWildcardConversion in the conversion \a options.
1925
1926 \sa escape()
1927*/
1928QString QRegularExpression::wildcardToRegularExpression(QStringView pattern, WildcardConversionOptions options)
1929{
1930 const qsizetype wclen = pattern.size();
1931 QString rx;
1932 rx.reserve(asize: wclen + wclen / 16);
1933 qsizetype i = 0;
1934 const QChar *wc = pattern.data();
1935
1936 struct GlobSettings {
1937 char16_t nativePathSeparator;
1938 QStringView starEscape;
1939 QStringView questionMarkEscape;
1940 };
1941
1942 const GlobSettings settings = [options]() {
1943 if (options.testFlag(flag: NonPathWildcardConversion)) {
1944 // using [\d\D] to mean "match everything";
1945 // dot doesn't match newlines, unless in /s mode
1946 return GlobSettings{ .nativePathSeparator: u'\0', .starEscape: u"[\\d\\D]*", .questionMarkEscape: u"[\\d\\D]" };
1947 } else {
1948#ifdef Q_OS_WIN
1949 return GlobSettings{ u'\\', u"[^/\\\\]*", u"[^/\\\\]" };
1950#else
1951 return GlobSettings{ .nativePathSeparator: u'/', .starEscape: u"[^/]*", .questionMarkEscape: u"[^/]" };
1952#endif
1953 }
1954 }();
1955
1956 while (i < wclen) {
1957 const QChar c = wc[i++];
1958 switch (c.unicode()) {
1959 case '*':
1960 rx += settings.starEscape;
1961 break;
1962 case '?':
1963 rx += settings.questionMarkEscape;
1964 break;
1965 // When not using filepath globbing: \ is escaped, / is itself
1966 // When using filepath globbing:
1967 // * Unix: \ gets escaped. / is itself
1968 // * Windows: \ and / can match each other -- they become [/\\] in regexp
1969 case '\\':
1970#ifdef Q_OS_WIN
1971 if (options.testFlag(NonPathWildcardConversion))
1972 rx += u"\\\\";
1973 else
1974 rx += u"[/\\\\]";
1975 break;
1976 case '/':
1977 if (options.testFlag(NonPathWildcardConversion))
1978 rx += u'/';
1979 else
1980 rx += u"[/\\\\]";
1981 break;
1982#endif
1983 case '$':
1984 case '(':
1985 case ')':
1986 case '+':
1987 case '.':
1988 case '^':
1989 case '{':
1990 case '|':
1991 case '}':
1992 rx += u'\\';
1993 rx += c;
1994 break;
1995 case '[':
1996 rx += c;
1997 // Support for the [!abc] or [!a-c] syntax
1998 if (i < wclen) {
1999 if (wc[i] == u'!') {
2000 rx += u'^';
2001 ++i;
2002 }
2003
2004 if (i < wclen && wc[i] == u']')
2005 rx += wc[i++];
2006
2007 while (i < wclen && wc[i] != u']') {
2008 if (!options.testFlag(flag: NonPathWildcardConversion)) {
2009 // The '/' appearing in a character class invalidates the
2010 // regular expression parsing. It also concerns '\\' on
2011 // Windows OS types.
2012 if (wc[i] == u'/' || wc[i] == settings.nativePathSeparator)
2013 return rx;
2014 }
2015 if (wc[i] == u'\\')
2016 rx += u'\\';
2017 rx += wc[i++];
2018 }
2019 }
2020 break;
2021 default:
2022 rx += c;
2023 break;
2024 }
2025 }
2026
2027 if (!(options & UnanchoredWildcardConversion))
2028 rx = anchoredPattern(expression: rx);
2029
2030 return rx;
2031}
2032
2033/*!
2034 \since 6.0
2035 Returns a regular expression of the glob pattern \a pattern. The regular expression
2036 will be case sensitive if \a cs is \l{Qt::CaseSensitive}, and converted according to
2037 \a options.
2038
2039 Equivalent to
2040 \code
2041 auto reOptions = cs == Qt::CaseSensitive ? QRegularExpression::NoPatternOption :
2042 QRegularExpression::CaseInsensitiveOption;
2043 return QRegularExpression(wildcardToRegularExpression(str, options), reOptions);
2044 \endcode
2045*/
2046QRegularExpression QRegularExpression::fromWildcard(QStringView pattern, Qt::CaseSensitivity cs,
2047 WildcardConversionOptions options)
2048{
2049 auto reOptions = cs == Qt::CaseSensitive ? QRegularExpression::NoPatternOption :
2050 QRegularExpression::CaseInsensitiveOption;
2051 return QRegularExpression(wildcardToRegularExpression(pattern, options), reOptions);
2052}
2053
2054/*!
2055 \fn QRegularExpression::anchoredPattern(const QString &expression)
2056 \since 5.12
2057 \overload
2058*/
2059
2060/*!
2061 \since 5.15
2062
2063 Returns the \a expression wrapped between the \c{\A} and \c{\z} anchors to
2064 be used for exact matching.
2065*/
2066QString QRegularExpression::anchoredPattern(QStringView expression)
2067{
2068 return QString()
2069 + "\\A(?:"_L1
2070 + expression
2071 + ")\\z"_L1;
2072}
2073
2074/*!
2075 \since 5.1
2076
2077 Constructs a valid, empty QRegularExpressionMatch object. The regular
2078 expression is set to a default-constructed one; the match type to
2079 QRegularExpression::NoMatch and the match options to
2080 QRegularExpression::NoMatchOption.
2081
2082 The object will report no match through the hasMatch() and the
2083 hasPartialMatch() member functions.
2084*/
2085QRegularExpressionMatch::QRegularExpressionMatch()
2086 : d(new QRegularExpressionMatchPrivate(QRegularExpression(),
2087 QString(),
2088 QStringView(),
2089 QRegularExpression::NoMatch,
2090 QRegularExpression::NoMatchOption))
2091{
2092 d->isValid = true;
2093}
2094
2095/*!
2096 Destroys the match result.
2097*/
2098QRegularExpressionMatch::~QRegularExpressionMatch()
2099{
2100}
2101
2102QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QRegularExpressionMatchPrivate)
2103
2104/*!
2105 Constructs a match result by copying the result of the given \a match.
2106
2107 \sa operator=()
2108*/
2109QRegularExpressionMatch::QRegularExpressionMatch(const QRegularExpressionMatch &match)
2110 : d(match.d)
2111{
2112}
2113
2114/*!
2115 \fn QRegularExpressionMatch::QRegularExpressionMatch(QRegularExpressionMatch &&match)
2116
2117 \since 6.1
2118
2119 Constructs a match result by moving the result from the given \a match.
2120
2121 Note that a moved-from QRegularExpressionMatch can only be destroyed or
2122 assigned to. The effect of calling other functions than the destructor
2123 or one of the assignment operators is undefined.
2124
2125 \sa operator=()
2126*/
2127
2128/*!
2129 Assigns the match result \a match to this object, and returns a reference
2130 to the copy.
2131*/
2132QRegularExpressionMatch &QRegularExpressionMatch::operator=(const QRegularExpressionMatch &match)
2133{
2134 d = match.d;
2135 return *this;
2136}
2137
2138/*!
2139 \fn QRegularExpressionMatch &QRegularExpressionMatch::operator=(QRegularExpressionMatch &&match)
2140
2141 Move-assigns the match result \a match to this object, and returns a
2142 reference to the result.
2143
2144 Note that a moved-from QRegularExpressionMatch can only be destroyed or
2145 assigned to. The effect of calling other functions than the destructor
2146 or one of the assignment operators is undefined.
2147*/
2148
2149/*!
2150 \fn void QRegularExpressionMatch::swap(QRegularExpressionMatch &other)
2151
2152 Swaps the match result \a other with this match result. This
2153 operation is very fast and never fails.
2154*/
2155
2156/*!
2157 \internal
2158*/
2159QRegularExpressionMatch::QRegularExpressionMatch(QRegularExpressionMatchPrivate &dd)
2160 : d(&dd)
2161{
2162}
2163
2164/*!
2165 Returns the QRegularExpression object whose match() function returned this
2166 object.
2167
2168 \sa QRegularExpression::match(), matchType(), matchOptions()
2169*/
2170QRegularExpression QRegularExpressionMatch::regularExpression() const
2171{
2172 return d->regularExpression;
2173}
2174
2175
2176/*!
2177 Returns the match type that was used to get this QRegularExpressionMatch
2178 object, that is, the match type that was passed to
2179 QRegularExpression::match() or QRegularExpression::globalMatch().
2180
2181 \sa QRegularExpression::match(), regularExpression(), matchOptions()
2182*/
2183QRegularExpression::MatchType QRegularExpressionMatch::matchType() const
2184{
2185 return d->matchType;
2186}
2187
2188/*!
2189 Returns the match options that were used to get this
2190 QRegularExpressionMatch object, that is, the match options that were passed
2191 to QRegularExpression::match() or QRegularExpression::globalMatch().
2192
2193 \sa QRegularExpression::match(), regularExpression(), matchType()
2194*/
2195QRegularExpression::MatchOptions QRegularExpressionMatch::matchOptions() const
2196{
2197 return d->matchOptions;
2198}
2199
2200/*!
2201 Returns the index of the last capturing group that captured something,
2202 including the implicit capturing group 0. This can be used to extract all
2203 the substrings that were captured:
2204
2205 \snippet code/src_corelib_text_qregularexpression.cpp 28
2206
2207 Note that some of the capturing groups with an index less than
2208 lastCapturedIndex() could have not matched, and therefore captured nothing.
2209
2210 If the regular expression did not match, this function returns -1.
2211
2212 \sa hasCaptured(), captured(), capturedStart(), capturedEnd(), capturedLength()
2213*/
2214int QRegularExpressionMatch::lastCapturedIndex() const
2215{
2216 return d->capturedCount - 1;
2217}
2218
2219/*!
2220 \fn bool QRegularExpressionMatch::hasCaptured(const QString &name) const
2221 \fn bool QRegularExpressionMatch::hasCaptured(QStringView name) const
2222 \since 6.3
2223
2224 Returns true if the capturing group named \a name captured something
2225 in the subject string, and false otherwise (or if there is no
2226 capturing group called \a name).
2227
2228 \note Some capturing groups in a regular expression may not have
2229 captured anything even if the regular expression matched. This may
2230 happen, for instance, if a conditional operator is used in the
2231 pattern:
2232
2233 \snippet code/src_corelib_text_qregularexpression.cpp 36
2234
2235 Similarly, a capturing group may capture a substring of length 0;
2236 this function will return \c{true} for such a capturing group.
2237
2238 \sa captured(), hasMatch()
2239*/
2240bool QRegularExpressionMatch::hasCaptured(QStringView name) const
2241{
2242 const int nth = d->regularExpression.d->captureIndexForName(name);
2243 return hasCaptured(nth);
2244}
2245
2246/*!
2247 \since 6.3
2248
2249 Returns true if the \a nth capturing group captured something
2250 in the subject string, and false otherwise (or if there is no
2251 such capturing group).
2252
2253 \note The implicit capturing group number 0 captures the substring
2254 matched by the entire pattern.
2255
2256 \note Some capturing groups in a regular expression may not have
2257 captured anything even if the regular expression matched. This may
2258 happen, for instance, if a conditional operator is used in the
2259 pattern:
2260
2261 \snippet code/src_corelib_text_qregularexpression.cpp 36
2262
2263 Similarly, a capturing group may capture a substring of length 0;
2264 this function will return \c{true} for such a capturing group.
2265
2266 \sa captured(), lastCapturedIndex(), hasMatch()
2267*/
2268bool QRegularExpressionMatch::hasCaptured(int nth) const
2269{
2270 if (nth < 0 || nth > lastCapturedIndex())
2271 return false;
2272
2273 return d->capturedOffsets.at(i: nth * 2) != -1;
2274}
2275
2276/*!
2277 Returns the substring captured by the \a nth capturing group.
2278
2279 If the \a nth capturing group did not capture a string, or if there is no
2280 such capturing group, returns a null QString.
2281
2282 \note The implicit capturing group number 0 captures the substring matched
2283 by the entire pattern.
2284
2285 \sa capturedView(), lastCapturedIndex(), capturedStart(), capturedEnd(),
2286 capturedLength(), QString::isNull()
2287*/
2288QString QRegularExpressionMatch::captured(int nth) const
2289{
2290 return capturedView(nth).toString();
2291}
2292
2293/*!
2294 \since 5.10
2295
2296 Returns a view of the substring captured by the \a nth capturing group.
2297
2298 If the \a nth capturing group did not capture a string, or if there is no
2299 such capturing group, returns a null QStringView.
2300
2301 \note The implicit capturing group number 0 captures the substring matched
2302 by the entire pattern.
2303
2304 \sa captured(), lastCapturedIndex(), capturedStart(), capturedEnd(),
2305 capturedLength(), QStringView::isNull()
2306*/
2307QStringView QRegularExpressionMatch::capturedView(int nth) const
2308{
2309 if (!hasCaptured(nth))
2310 return QStringView();
2311
2312 qsizetype start = capturedStart(nth);
2313
2314 if (start == -1) // didn't capture
2315 return QStringView();
2316
2317 return d->subject.mid(pos: start, n: capturedLength(nth));
2318}
2319
2320/*! \fn QString QRegularExpressionMatch::captured(const QString &name) const
2321
2322 Returns the substring captured by the capturing group named \a name.
2323
2324 If the named capturing group \a name did not capture a string, or if
2325 there is no capturing group named \a name, returns a null QString.
2326
2327 \sa capturedView(), capturedStart(), capturedEnd(), capturedLength(),
2328 QString::isNull()
2329*/
2330
2331/*!
2332 \since 5.10
2333
2334 Returns the substring captured by the capturing group named \a name.
2335
2336 If the named capturing group \a name did not capture a string, or if
2337 there is no capturing group named \a name, returns a null QString.
2338
2339 \sa capturedView(), capturedStart(), capturedEnd(), capturedLength(),
2340 QString::isNull()
2341*/
2342QString QRegularExpressionMatch::captured(QStringView name) const
2343{
2344 if (name.isEmpty()) {
2345 qWarning(msg: "QRegularExpressionMatch::captured: empty capturing group name passed");
2346 return QString();
2347 }
2348
2349 return capturedView(name).toString();
2350}
2351
2352/*!
2353 \since 5.10
2354
2355 Returns a view of the string captured by the capturing group named \a
2356 name.
2357
2358 If the named capturing group \a name did not capture a string, or if
2359 there is no capturing group named \a name, returns a null QStringView.
2360
2361 \sa captured(), capturedStart(), capturedEnd(), capturedLength(),
2362 QStringView::isNull()
2363*/
2364QStringView QRegularExpressionMatch::capturedView(QStringView name) const
2365{
2366 if (name.isEmpty()) {
2367 qWarning(msg: "QRegularExpressionMatch::capturedView: empty capturing group name passed");
2368 return QStringView();
2369 }
2370 int nth = d->regularExpression.d->captureIndexForName(name);
2371 if (nth == -1)
2372 return QStringView();
2373 return capturedView(nth);
2374}
2375
2376/*!
2377 Returns a list of all strings captured by capturing groups, in the order
2378 the groups themselves appear in the pattern string. The list includes the
2379 implicit capturing group number 0, capturing the substring matched by the
2380 entire pattern.
2381*/
2382QStringList QRegularExpressionMatch::capturedTexts() const
2383{
2384 QStringList texts;
2385 texts.reserve(asize: d->capturedCount);
2386 for (int i = 0; i < d->capturedCount; ++i)
2387 texts << captured(nth: i);
2388 return texts;
2389}
2390
2391/*!
2392 Returns the offset inside the subject string corresponding to the
2393 starting position of the substring captured by the \a nth capturing group.
2394 If the \a nth capturing group did not capture a string or doesn't exist,
2395 returns -1.
2396
2397 \sa capturedEnd(), capturedLength(), captured()
2398*/
2399qsizetype QRegularExpressionMatch::capturedStart(int nth) const
2400{
2401 if (!hasCaptured(nth))
2402 return -1;
2403
2404 return d->capturedOffsets.at(i: nth * 2);
2405}
2406
2407/*!
2408 Returns the length of the substring captured by the \a nth capturing group.
2409
2410 \note This function returns 0 if the \a nth capturing group did not capture
2411 a string or doesn't exist.
2412
2413 \sa capturedStart(), capturedEnd(), captured()
2414*/
2415qsizetype QRegularExpressionMatch::capturedLength(int nth) const
2416{
2417 // bound checking performed by these two functions
2418 return capturedEnd(nth) - capturedStart(nth);
2419}
2420
2421/*!
2422 Returns the offset inside the subject string immediately after the ending
2423 position of the substring captured by the \a nth capturing group. If the \a
2424 nth capturing group did not capture a string or doesn't exist, returns -1.
2425
2426 \sa capturedStart(), capturedLength(), captured()
2427*/
2428qsizetype QRegularExpressionMatch::capturedEnd(int nth) const
2429{
2430 if (!hasCaptured(nth))
2431 return -1;
2432
2433 return d->capturedOffsets.at(i: nth * 2 + 1);
2434}
2435
2436/*! \fn qsizetype QRegularExpressionMatch::capturedStart(const QString &name) const
2437
2438 Returns the offset inside the subject string corresponding to the starting
2439 position of the substring captured by the capturing group named \a name.
2440 If the capturing group named \a name did not capture a string or doesn't
2441 exist, returns -1.
2442
2443 \sa capturedEnd(), capturedLength(), captured()
2444*/
2445
2446/*! \fn qsizetype QRegularExpressionMatch::capturedLength(const QString &name) const
2447
2448 Returns the length of the substring captured by the capturing group named
2449 \a name.
2450
2451 \note This function returns 0 if the capturing group named \a name did not
2452 capture a string or doesn't exist.
2453
2454 \sa capturedStart(), capturedEnd(), captured()
2455*/
2456
2457/*! \fn qsizetype QRegularExpressionMatch::capturedEnd(const QString &name) const
2458
2459 Returns the offset inside the subject string immediately after the ending
2460 position of the substring captured by the capturing group named \a name. If
2461 the capturing group named \a name did not capture a string or doesn't
2462 exist, returns -1.
2463
2464 \sa capturedStart(), capturedLength(), captured()
2465*/
2466
2467/*!
2468 \since 5.10
2469
2470 Returns the offset inside the subject string corresponding to the starting
2471 position of the substring captured by the capturing group named \a name.
2472 If the capturing group named \a name did not capture a string or doesn't
2473 exist, returns -1.
2474
2475 \sa capturedEnd(), capturedLength(), captured()
2476*/
2477qsizetype QRegularExpressionMatch::capturedStart(QStringView name) const
2478{
2479 if (name.isEmpty()) {
2480 qWarning(msg: "QRegularExpressionMatch::capturedStart: empty capturing group name passed");
2481 return -1;
2482 }
2483 int nth = d->regularExpression.d->captureIndexForName(name);
2484 if (nth == -1)
2485 return -1;
2486 return capturedStart(nth);
2487}
2488
2489/*!
2490 \since 5.10
2491
2492 Returns the length of the substring captured by the capturing group named
2493 \a name.
2494
2495 \note This function returns 0 if the capturing group named \a name did not
2496 capture a string or doesn't exist.
2497
2498 \sa capturedStart(), capturedEnd(), captured()
2499*/
2500qsizetype QRegularExpressionMatch::capturedLength(QStringView name) const
2501{
2502 if (name.isEmpty()) {
2503 qWarning(msg: "QRegularExpressionMatch::capturedLength: empty capturing group name passed");
2504 return 0;
2505 }
2506 int nth = d->regularExpression.d->captureIndexForName(name);
2507 if (nth == -1)
2508 return 0;
2509 return capturedLength(nth);
2510}
2511
2512/*!
2513 \since 5.10
2514
2515 Returns the offset inside the subject string immediately after the ending
2516 position of the substring captured by the capturing group named \a name. If
2517 the capturing group named \a name did not capture a string or doesn't
2518 exist, returns -1.
2519
2520 \sa capturedStart(), capturedLength(), captured()
2521*/
2522qsizetype QRegularExpressionMatch::capturedEnd(QStringView name) const
2523{
2524 if (name.isEmpty()) {
2525 qWarning(msg: "QRegularExpressionMatch::capturedEnd: empty capturing group name passed");
2526 return -1;
2527 }
2528 int nth = d->regularExpression.d->captureIndexForName(name);
2529 if (nth == -1)
2530 return -1;
2531 return capturedEnd(nth);
2532}
2533
2534/*!
2535 Returns \c true if the regular expression matched against the subject string,
2536 or false otherwise.
2537
2538 \sa QRegularExpression::match(), hasPartialMatch()
2539*/
2540bool QRegularExpressionMatch::hasMatch() const
2541{
2542 return d->hasMatch;
2543}
2544
2545/*!
2546 Returns \c true if the regular expression partially matched against the
2547 subject string, or false otherwise.
2548
2549 \note Only a match that explicitly used the one of the partial match types
2550 can yield a partial match. Still, if such a match succeeds totally, this
2551 function will return false, while hasMatch() will return true.
2552
2553 \sa QRegularExpression::match(), QRegularExpression::MatchType, hasMatch()
2554*/
2555bool QRegularExpressionMatch::hasPartialMatch() const
2556{
2557 return d->hasPartialMatch;
2558}
2559
2560/*!
2561 Returns \c true if the match object was obtained as a result from the
2562 QRegularExpression::match() function invoked on a valid QRegularExpression
2563 object; returns \c false if the QRegularExpression was invalid.
2564
2565 \sa QRegularExpression::match(), QRegularExpression::isValid()
2566*/
2567bool QRegularExpressionMatch::isValid() const
2568{
2569 return d->isValid;
2570}
2571
2572/*!
2573 \internal
2574*/
2575QRegularExpressionMatchIterator::QRegularExpressionMatchIterator(QRegularExpressionMatchIteratorPrivate &dd)
2576 : d(&dd)
2577{
2578}
2579
2580/*!
2581 \since 5.1
2582
2583 Constructs an empty, valid QRegularExpressionMatchIterator object. The
2584 regular expression is set to a default-constructed one; the match type to
2585 QRegularExpression::NoMatch and the match options to
2586 QRegularExpression::NoMatchOption.
2587
2588 Invoking the hasNext() member function on the constructed object will
2589 return false, as the iterator is not iterating on a valid sequence of
2590 matches.
2591*/
2592QRegularExpressionMatchIterator::QRegularExpressionMatchIterator()
2593 : d(new QRegularExpressionMatchIteratorPrivate(QRegularExpression(),
2594 QRegularExpression::NoMatch,
2595 QRegularExpression::NoMatchOption,
2596 QRegularExpressionMatch()))
2597{
2598}
2599
2600/*!
2601 Destroys the QRegularExpressionMatchIterator object.
2602*/
2603QRegularExpressionMatchIterator::~QRegularExpressionMatchIterator()
2604{
2605}
2606
2607QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QRegularExpressionMatchIteratorPrivate)
2608
2609/*!
2610 Constructs a QRegularExpressionMatchIterator object as a copy of \a
2611 iterator.
2612
2613 \sa operator=()
2614*/
2615QRegularExpressionMatchIterator::QRegularExpressionMatchIterator(const QRegularExpressionMatchIterator &iterator)
2616 : d(iterator.d)
2617{
2618}
2619
2620/*!
2621 \fn QRegularExpressionMatchIterator::QRegularExpressionMatchIterator(QRegularExpressionMatchIterator &&iterator)
2622
2623 \since 6.1
2624
2625 Constructs a QRegularExpressionMatchIterator object by moving from \a iterator.
2626
2627 Note that a moved-from QRegularExpressionMatchIterator can only be destroyed
2628 or assigned to. The effect of calling other functions than the destructor
2629 or one of the assignment operators is undefined.
2630
2631 \sa operator=()
2632*/
2633
2634/*!
2635 Assigns the iterator \a iterator to this object, and returns a reference to
2636 the copy.
2637*/
2638QRegularExpressionMatchIterator &QRegularExpressionMatchIterator::operator=(const QRegularExpressionMatchIterator &iterator)
2639{
2640 d = iterator.d;
2641 return *this;
2642}
2643
2644/*!
2645 \fn QRegularExpressionMatchIterator &QRegularExpressionMatchIterator::operator=(QRegularExpressionMatchIterator &&iterator)
2646
2647 Move-assigns the \a iterator to this object, and returns a reference to the
2648 result.
2649
2650 Note that a moved-from QRegularExpressionMatchIterator can only be destroyed
2651 or assigned to. The effect of calling other functions than the destructor
2652 or one of the assignment operators is undefined.
2653*/
2654
2655/*!
2656 \fn void QRegularExpressionMatchIterator::swap(QRegularExpressionMatchIterator &other)
2657
2658 Swaps the iterator \a other with this iterator object. This operation is
2659 very fast and never fails.
2660*/
2661
2662/*!
2663 Returns \c true if the iterator object was obtained as a result from the
2664 QRegularExpression::globalMatch() function invoked on a valid
2665 QRegularExpression object; returns \c false if the QRegularExpression was
2666 invalid.
2667
2668 \sa QRegularExpression::globalMatch(), QRegularExpression::isValid()
2669*/
2670bool QRegularExpressionMatchIterator::isValid() const
2671{
2672 return d->next.isValid();
2673}
2674
2675/*!
2676 Returns \c true if there is at least one match result ahead of the iterator;
2677 otherwise it returns \c false.
2678
2679 \sa next()
2680*/
2681bool QRegularExpressionMatchIterator::hasNext() const
2682{
2683 return d->hasNext();
2684}
2685
2686/*!
2687 Returns the next match result without moving the iterator.
2688
2689 \note Calling this function when the iterator is at the end of the result
2690 set leads to undefined results.
2691*/
2692QRegularExpressionMatch QRegularExpressionMatchIterator::peekNext() const
2693{
2694 if (!hasNext())
2695 qWarning(msg: "QRegularExpressionMatchIterator::peekNext() called on an iterator already at end");
2696
2697 return d->next;
2698}
2699
2700/*!
2701 Returns the next match result and advances the iterator by one position.
2702
2703 \note Calling this function when the iterator is at the end of the result
2704 set leads to undefined results.
2705*/
2706QRegularExpressionMatch QRegularExpressionMatchIterator::next()
2707{
2708 if (!hasNext()) {
2709 qWarning(msg: "QRegularExpressionMatchIterator::next() called on an iterator already at end");
2710 return d.constData()->next;
2711 }
2712
2713 d.detach();
2714 return std::exchange(obj&: d->next, new_val: d->next.d.constData()->nextMatch());
2715}
2716
2717/*!
2718 Returns the QRegularExpression object whose globalMatch() function returned
2719 this object.
2720
2721 \sa QRegularExpression::globalMatch(), matchType(), matchOptions()
2722*/
2723QRegularExpression QRegularExpressionMatchIterator::regularExpression() const
2724{
2725 return d->regularExpression;
2726}
2727
2728/*!
2729 Returns the match type that was used to get this
2730 QRegularExpressionMatchIterator object, that is, the match type that was
2731 passed to QRegularExpression::globalMatch().
2732
2733 \sa QRegularExpression::globalMatch(), regularExpression(), matchOptions()
2734*/
2735QRegularExpression::MatchType QRegularExpressionMatchIterator::matchType() const
2736{
2737 return d->matchType;
2738}
2739
2740/*!
2741 Returns the match options that were used to get this
2742 QRegularExpressionMatchIterator object, that is, the match options that
2743 were passed to QRegularExpression::globalMatch().
2744
2745 \sa QRegularExpression::globalMatch(), regularExpression(), matchType()
2746*/
2747QRegularExpression::MatchOptions QRegularExpressionMatchIterator::matchOptions() const
2748{
2749 return d->matchOptions;
2750}
2751
2752/*!
2753 \internal
2754*/
2755QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
2756{
2757 return QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator(iterator);
2758}
2759
2760/*!
2761 \fn QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel end(const QRegularExpressionMatchIterator &)
2762 \internal
2763*/
2764
2765#ifndef QT_NO_DATASTREAM
2766/*!
2767 \relates QRegularExpression
2768
2769 Writes the regular expression \a re to stream \a out.
2770
2771 \sa {Serializing Qt Data Types}
2772*/
2773QDataStream &operator<<(QDataStream &out, const QRegularExpression &re)
2774{
2775 out << re.pattern() << quint32(re.patternOptions().toInt());
2776 return out;
2777}
2778
2779/*!
2780 \relates QRegularExpression
2781
2782 Reads a regular expression from stream \a in into \a re.
2783
2784 \sa {Serializing Qt Data Types}
2785*/
2786QDataStream &operator>>(QDataStream &in, QRegularExpression &re)
2787{
2788 QString pattern;
2789 quint32 patternOptions;
2790 in >> pattern >> patternOptions;
2791 re.setPattern(pattern);
2792 re.setPatternOptions(QRegularExpression::PatternOptions::fromInt(i: patternOptions));
2793 return in;
2794}
2795#endif
2796
2797#ifndef QT_NO_DEBUG_STREAM
2798/*!
2799 \relates QRegularExpression
2800
2801 Writes the regular expression \a re into the debug object \a debug for
2802 debugging purposes.
2803
2804 \sa {Debugging Techniques}
2805*/
2806QDebug operator<<(QDebug debug, const QRegularExpression &re)
2807{
2808 QDebugStateSaver saver(debug);
2809 debug.nospace() << "QRegularExpression(" << re.pattern() << ", " << re.patternOptions() << ')';
2810 return debug;
2811}
2812
2813/*!
2814 \relates QRegularExpression
2815
2816 Writes the pattern options \a patternOptions into the debug object \a debug
2817 for debugging purposes.
2818
2819 \sa {Debugging Techniques}
2820*/
2821QDebug operator<<(QDebug debug, QRegularExpression::PatternOptions patternOptions)
2822{
2823 QDebugStateSaver saver(debug);
2824 QByteArray flags;
2825
2826 if (patternOptions == QRegularExpression::NoPatternOption) {
2827 flags = "NoPatternOption";
2828 } else {
2829 flags.reserve(asize: 200); // worst case...
2830 if (patternOptions & QRegularExpression::CaseInsensitiveOption)
2831 flags.append(s: "CaseInsensitiveOption|");
2832 if (patternOptions & QRegularExpression::DotMatchesEverythingOption)
2833 flags.append(s: "DotMatchesEverythingOption|");
2834 if (patternOptions & QRegularExpression::MultilineOption)
2835 flags.append(s: "MultilineOption|");
2836 if (patternOptions & QRegularExpression::ExtendedPatternSyntaxOption)
2837 flags.append(s: "ExtendedPatternSyntaxOption|");
2838 if (patternOptions & QRegularExpression::InvertedGreedinessOption)
2839 flags.append(s: "InvertedGreedinessOption|");
2840 if (patternOptions & QRegularExpression::DontCaptureOption)
2841 flags.append(s: "DontCaptureOption|");
2842 if (patternOptions & QRegularExpression::UseUnicodePropertiesOption)
2843 flags.append(s: "UseUnicodePropertiesOption|");
2844 flags.chop(n: 1);
2845 }
2846
2847 debug.nospace() << "QRegularExpression::PatternOptions(" << flags << ')';
2848
2849 return debug;
2850}
2851/*!
2852 \relates QRegularExpressionMatch
2853
2854 Writes the match object \a match into the debug object \a debug for
2855 debugging purposes.
2856
2857 \sa {Debugging Techniques}
2858*/
2859QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match)
2860{
2861 QDebugStateSaver saver(debug);
2862 debug.nospace() << "QRegularExpressionMatch(";
2863
2864 if (!match.isValid()) {
2865 debug << "Invalid)";
2866 return debug;
2867 }
2868
2869 debug << "Valid";
2870
2871 if (match.hasMatch()) {
2872 debug << ", has match: ";
2873 for (int i = 0; i <= match.lastCapturedIndex(); ++i) {
2874 debug << i
2875 << ":(" << match.capturedStart(nth: i) << ", " << match.capturedEnd(nth: i)
2876 << ", " << match.captured(nth: i) << ')';
2877 if (i < match.lastCapturedIndex())
2878 debug << ", ";
2879 }
2880 } else if (match.hasPartialMatch()) {
2881 debug << ", has partial match: ("
2882 << match.capturedStart(nth: 0) << ", "
2883 << match.capturedEnd(nth: 0) << ", "
2884 << match.captured(nth: 0) << ')';
2885 } else {
2886 debug << ", no match";
2887 }
2888
2889 debug << ')';
2890
2891 return debug;
2892}
2893#endif
2894
2895// fool lupdate: make it extract those strings for translation, but don't put them
2896// inside Qt -- they're already inside libpcre (cf. man 3 pcreapi, pcre_compile.c).
2897#if 0
2898
2899/* PCRE is a library of functions to support regular expressions whose syntax
2900and semantics are as close as possible to those of the Perl 5 language.
2901
2902 Written by Philip Hazel
2903 Original API code Copyright (c) 1997-2012 University of Cambridge
2904 New API code Copyright (c) 2015 University of Cambridge
2905
2906-----------------------------------------------------------------------------
2907Redistribution and use in source and binary forms, with or without
2908modification, are permitted provided that the following conditions are met:
2909
2910 * Redistributions of source code must retain the above copyright notice,
2911 this list of conditions and the following disclaimer.
2912
2913 * Redistributions in binary form must reproduce the above copyright
2914 notice, this list of conditions and the following disclaimer in the
2915 documentation and/or other materials provided with the distribution.
2916
2917 * Neither the name of the University of Cambridge nor the names of its
2918 contributors may be used to endorse or promote products derived from
2919 this software without specific prior written permission.
2920
2921THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2922AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2923IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2924ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2925LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2926CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2927SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2928INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2929CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2930ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2931POSSIBILITY OF SUCH DAMAGE.
2932-----------------------------------------------------------------------------
2933*/
2934
2935static const char *pcreCompileErrorCodes[] =
2936{
2937 QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
2938 QT_TRANSLATE_NOOP("QRegularExpression", "\\ at end of pattern"),
2939 QT_TRANSLATE_NOOP("QRegularExpression", "\\c at end of pattern"),
2940 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character follows \\"),
2941 QT_TRANSLATE_NOOP("QRegularExpression", "numbers out of order in {} quantifier"),
2942 QT_TRANSLATE_NOOP("QRegularExpression", "number too big in {} quantifier"),
2943 QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating ] for character class"),
2944 QT_TRANSLATE_NOOP("QRegularExpression", "escape sequence is invalid in character class"),
2945 QT_TRANSLATE_NOOP("QRegularExpression", "range out of order in character class"),
2946 QT_TRANSLATE_NOOP("QRegularExpression", "quantifier does not follow a repeatable item"),
2947 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unexpected repeat"),
2948 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (? or (?-"),
2949 QT_TRANSLATE_NOOP("QRegularExpression", "POSIX named classes are supported only within a class"),
2950 QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
2951 QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis"),
2952 QT_TRANSLATE_NOOP("QRegularExpression", "reference to non-existent subpattern"),
2953 QT_TRANSLATE_NOOP("QRegularExpression", "pattern passed as NULL"),
2954 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognised compile-time option bit(s)"),
2955 QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after (?# comment"),
2956 QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
2957 QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too large"),
2958 QT_TRANSLATE_NOOP("QRegularExpression", "failed to allocate heap memory"),
2959 QT_TRANSLATE_NOOP("QRegularExpression", "unmatched closing parenthesis"),
2960 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: code overflow"),
2961 QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis for condition"),
2962 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is not fixed length"),
2963 QT_TRANSLATE_NOOP("QRegularExpression", "a relative value of zero is not allowed"),
2964 QT_TRANSLATE_NOOP("QRegularExpression", "conditional subpattern contains more than two branches"),
2965 QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?( or (?(?C)"),
2966 QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+ or (?-"),
2967 QT_TRANSLATE_NOOP("QRegularExpression", "unknown POSIX class name"),
2968 QT_TRANSLATE_NOOP("QRegularExpression", "internal error in pcre2_study(): should not occur"),
2969 QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have Unicode support"),
2970 QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"),
2971 QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\x{} or \\o{} is too large"),
2972 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind is too complicated"),
2973 QT_TRANSLATE_NOOP("QRegularExpression", "\\C is not allowed in a lookbehind assertion in UTF-" "16" " mode"),
2974 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2 does not support \\F, \\L, \\l, \\N{name}, \\U, or \\u"),
2975 QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is greater than 255"),
2976 QT_TRANSLATE_NOOP("QRegularExpression", "closing parenthesis for (?C expected"),
2977 QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in (*VERB) name"),
2978 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?P"),
2979 QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in subpattern name (missing terminator?)"),
2980 QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name (PCRE2_DUPNAMES not set)"),
2981 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name must start with a non-digit"),
2982 QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have support for \\P, \\p, or \\X"),
2983 QT_TRANSLATE_NOOP("QRegularExpression", "malformed \\P or \\p sequence"),
2984 QT_TRANSLATE_NOOP("QRegularExpression", "unknown property name after \\P or \\p"),
2985 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum " "32" " code units)"),
2986 QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum " "10000" ")"),
2987 QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"),
2988 QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 in 8-bit non-UTF-8 mode"),
2989 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: overran compiling workspace"),
2990 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: previously-checked referenced subpattern not found"),
2991 QT_TRANSLATE_NOOP("QRegularExpression", "DEFINE subpattern contains more than one branch"),
2992 QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"),
2993 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown newline setting"),
2994 QT_TRANSLATE_NOOP("QRegularExpression", "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number"),
2995 QT_TRANSLATE_NOOP("QRegularExpression", "(?R (recursive pattern call) must be followed by a closing parenthesis"),
2996 QT_TRANSLATE_NOOP("QRegularExpression", "obsolete error (should not occur)"),
2997 QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized or malformed"),
2998 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern number is too big"),
2999 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name expected"),
3000 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: parsed pattern overflow"),
3001 QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"),
3002 QT_TRANSLATE_NOOP("QRegularExpression", "different names for subpatterns of the same number are not allowed"),
3003 QT_TRANSLATE_NOOP("QRegularExpression", "(*MARK) must have an argument"),
3004 QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
3005 QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a printable ASCII character"),
3006 QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a letter or one of [\\]^_?"),
3007 QT_TRANSLATE_NOOP("QRegularExpression", "\\k is not followed by a braced, angle-bracketed, or quoted name"),
3008 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown meta code in check_lookbehinds()"),
3009 QT_TRANSLATE_NOOP("QRegularExpression", "\\N is not supported in a class"),
3010 QT_TRANSLATE_NOOP("QRegularExpression", "callout string is too long"),
3011 QT_TRANSLATE_NOOP("QRegularExpression", "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)"),
3012 QT_TRANSLATE_NOOP("QRegularExpression", "using UTF is disabled by the application"),
3013 QT_TRANSLATE_NOOP("QRegularExpression", "using UCP is disabled by the application"),
3014 QT_TRANSLATE_NOOP("QRegularExpression", "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)"),
3015 QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\u.... sequence is too large"),
3016 QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{} or \\N{U+}"),
3017 QT_TRANSLATE_NOOP("QRegularExpression", "syntax error or number too big in (?(VERSION condition"),
3018 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in auto_possessify()"),
3019 QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating delimiter for callout with string argument"),
3020 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized string delimiter follows (?C"),
3021 QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled by the application"),
3022 QT_TRANSLATE_NOOP("QRegularExpression", "(?| and/or (?J: or (?x: parentheses are too deeply nested"),
3023 QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled in this PCRE2 library"),
3024 QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too complicated"),
3025 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is too long"),
3026 QT_TRANSLATE_NOOP("QRegularExpression", "pattern string is longer than the limit set by the application"),
3027 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown code in parsed pattern"),
3028 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: bad code value in parsed_skip()"),
3029 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode"),
3030 QT_TRANSLATE_NOOP("QRegularExpression", "invalid option bits with PCRE2_LITERAL"),
3031 QT_TRANSLATE_NOOP("QRegularExpression", "\\N{U+dddd} is supported only in Unicode (UTF) mode"),
3032 QT_TRANSLATE_NOOP("QRegularExpression", "invalid hyphen in option setting"),
3033 QT_TRANSLATE_NOOP("QRegularExpression", "(*alpha_assertion) not recognized"),
3034 QT_TRANSLATE_NOOP("QRegularExpression", "script runs require Unicode support, which this version of PCRE2 does not have"),
3035 QT_TRANSLATE_NOOP("QRegularExpression", "too many capturing groups (maximum 65535)"),
3036 QT_TRANSLATE_NOOP("QRegularExpression", "atomic assertion expected after (?( or (?(?C)"),
3037 QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
3038 QT_TRANSLATE_NOOP("QRegularExpression", "no match"),
3039 QT_TRANSLATE_NOOP("QRegularExpression", "partial match"),
3040 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 1 byte missing at end"),
3041 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 2 bytes missing at end"),
3042 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 3 bytes missing at end"),
3043 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 4 bytes missing at end"),
3044 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5 bytes missing at end"),
3045 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 2 top bits not 0x80"),
3046 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 3 top bits not 0x80"),
3047 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 4 top bits not 0x80"),
3048 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 5 top bits not 0x80"),
3049 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 6 top bits not 0x80"),
3050 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5-byte character is not allowed (RFC 3629)"),
3051 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 6-byte character is not allowed (RFC 3629)"),
3052 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points greater than 0x10ffff are not defined"),
3053 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points 0xd800-0xdfff are not defined"),
3054 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 2-byte sequence"),
3055 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 3-byte sequence"),
3056 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 4-byte sequence"),
3057 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 5-byte sequence"),
3058 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 6-byte sequence"),
3059 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: isolated byte with 0x80 bit set"),
3060 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: illegal byte (0xfe or 0xff)"),
3061 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: missing low surrogate at end"),
3062 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: invalid low surrogate"),
3063 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: isolated low surrogate"),
3064 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points 0xd800-0xdfff are not defined"),
3065 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points greater than 0x10ffff are not defined"),
3066 QT_TRANSLATE_NOOP("QRegularExpression", "bad data value"),
3067 QT_TRANSLATE_NOOP("QRegularExpression", "patterns do not all use the same character tables"),
3068 QT_TRANSLATE_NOOP("QRegularExpression", "magic number missing"),
3069 QT_TRANSLATE_NOOP("QRegularExpression", "pattern compiled in wrong mode: 8/16/32-bit error"),
3070 QT_TRANSLATE_NOOP("QRegularExpression", "bad offset value"),
3071 QT_TRANSLATE_NOOP("QRegularExpression", "bad option value"),
3072 QT_TRANSLATE_NOOP("QRegularExpression", "invalid replacement string"),
3073 QT_TRANSLATE_NOOP("QRegularExpression", "bad offset into UTF string"),
3074 QT_TRANSLATE_NOOP("QRegularExpression", "callout error code"),
3075 QT_TRANSLATE_NOOP("QRegularExpression", "invalid data in workspace for DFA restart"),
3076 QT_TRANSLATE_NOOP("QRegularExpression", "too much recursion for DFA matching"),
3077 QT_TRANSLATE_NOOP("QRegularExpression", "backreference condition or recursion test is not supported for DFA matching"),
3078 QT_TRANSLATE_NOOP("QRegularExpression", "function is not supported for DFA matching"),
3079 QT_TRANSLATE_NOOP("QRegularExpression", "pattern contains an item that is not supported for DFA matching"),
3080 QT_TRANSLATE_NOOP("QRegularExpression", "workspace size exceeded in DFA matching"),
3081 QT_TRANSLATE_NOOP("QRegularExpression", "internal error - pattern overwritten?"),
3082 QT_TRANSLATE_NOOP("QRegularExpression", "bad JIT option"),
3083 QT_TRANSLATE_NOOP("QRegularExpression", "JIT stack limit reached"),
3084 QT_TRANSLATE_NOOP("QRegularExpression", "match limit exceeded"),
3085 QT_TRANSLATE_NOOP("QRegularExpression", "no more memory"),
3086 QT_TRANSLATE_NOOP("QRegularExpression", "unknown substring"),
3087 QT_TRANSLATE_NOOP("QRegularExpression", "non-unique substring name"),
3088 QT_TRANSLATE_NOOP("QRegularExpression", "NULL argument passed"),
3089 QT_TRANSLATE_NOOP("QRegularExpression", "nested recursion at the same subject position"),
3090 QT_TRANSLATE_NOOP("QRegularExpression", "matching depth limit exceeded"),
3091 QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not available"),
3092 QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not set"),
3093 QT_TRANSLATE_NOOP("QRegularExpression", "offset limit set without PCRE2_USE_OFFSET_LIMIT"),
3094 QT_TRANSLATE_NOOP("QRegularExpression", "bad escape sequence in replacement string"),
3095 QT_TRANSLATE_NOOP("QRegularExpression", "expected closing curly bracket in replacement string"),
3096 QT_TRANSLATE_NOOP("QRegularExpression", "bad substitution in replacement string"),
3097 QT_TRANSLATE_NOOP("QRegularExpression", "match with end before start or start moved backwards is not supported"),
3098 QT_TRANSLATE_NOOP("QRegularExpression", "too many replacements (more than INT_MAX)"),
3099 QT_TRANSLATE_NOOP("QRegularExpression", "bad serialized data"),
3100 QT_TRANSLATE_NOOP("QRegularExpression", "heap limit exceeded"),
3101 QT_TRANSLATE_NOOP("QRegularExpression", "invalid syntax"),
3102 QT_TRANSLATE_NOOP("QRegularExpression", "internal error - duplicate substitution match"),
3103 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching")
3104};
3105#endif // #if 0
3106
3107QT_END_NAMESPACE
3108

source code of qtbase/src/corelib/text/qregularexpression.cpp