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 \ingroup string-processing
43
44 \keyword regular expression
45
46 \compares equality
47 Regular expressions, or \e{regexps}, are a very powerful tool to handle
48 strings and texts. This is useful in many contexts, e.g.,
49
50 \table
51 \row \li Validation
52 \li A regexp can test whether a substring meets some criteria,
53 e.g. is an integer or contains no whitespace.
54 \row \li Searching
55 \li A regexp provides more powerful pattern matching than
56 simple substring matching, e.g., match one of the words
57 \e{mail}, \e{letter} or \e{correspondence}, but none of the
58 words \e{email}, \e{mailman}, \e{mailer}, \e{letterbox}, etc.
59 \row \li Search and Replace
60 \li A regexp can replace all occurrences of a substring with a
61 different substring, e.g., replace all occurrences of \e{&}
62 with \e{\&amp;} except where the \e{&} is already followed by
63 an \e{amp;}.
64 \row \li String Splitting
65 \li A regexp can be used to identify where a string should be
66 split apart, e.g. splitting tab-delimited strings.
67 \endtable
68
69 This document is by no means a complete reference to pattern matching using
70 regular expressions, and the following parts will require the reader to
71 have some basic knowledge about Perl-like regular expressions and their
72 pattern syntax.
73
74 Good references about regular expressions include:
75
76 \list
77 \li \e {Mastering Regular Expressions} (Third Edition) by Jeffrey E. F.
78 Friedl, ISBN 0-596-52812-4;
79 \li the \l{https://pcre.org/original/doc/html/pcrepattern.html}
80 {pcrepattern(3)} man page, describing the pattern syntax supported by PCRE
81 (the reference implementation of Perl-compatible regular expressions);
82 \li the \l{http://perldoc.perl.org/perlre.html} {Perl's regular expression
83 documentation} and the \l{http://perldoc.perl.org/perlretut.html} {Perl's
84 regular expression tutorial}.
85 \endlist
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 \ingroup string-processing
449
450 \keyword regular expression match
451
452 A QRegularExpressionMatch object can be obtained by calling the
453 QRegularExpression::match() function, or as a single result of a global
454 match from a QRegularExpressionMatchIterator.
455
456 The success or the failure of a match attempt can be inspected by calling
457 the hasMatch() function. QRegularExpressionMatch also reports a successful
458 partial match through the hasPartialMatch() function.
459
460 In addition, QRegularExpressionMatch returns the substrings captured by the
461 capturing groups in the pattern string. The implicit capturing group with
462 index 0 captures the result of the whole match. The captured() function
463 returns each substring captured, either by the capturing group's index or
464 by its name:
465
466 \snippet code/src_corelib_text_qregularexpression.cpp 29
467
468 For each captured substring it is possible to query its starting and ending
469 offsets in the subject string by calling the capturedStart() and the
470 capturedEnd() function, respectively. The length of each captured
471 substring is available using the capturedLength() function.
472
473 The convenience function capturedTexts() will return \e{all} the captured
474 substrings at once (including the substring matched by the entire pattern)
475 in the order they have been captured by capturing groups; that is,
476 \c{captured(i) == capturedTexts().at(i)}.
477
478 You can retrieve the QRegularExpression object the subject string was
479 matched against by calling the regularExpression() function; the
480 match type and the match options are available as well by calling
481 the matchType() and the matchOptions() respectively.
482
483 Please refer to the QRegularExpression documentation for more information
484 about the Qt regular expression classes.
485
486 \sa QRegularExpression
487*/
488
489/*!
490 \class QRegularExpressionMatchIterator
491 \inmodule QtCore
492 \reentrant
493
494 \brief The QRegularExpressionMatchIterator class provides an iterator on
495 the results of a global match of a QRegularExpression object against a string.
496
497 \since 5.0
498
499 \ingroup tools
500 \ingroup shared
501 \ingroup string-processing
502
503 \keyword regular expression iterator
504
505 A QRegularExpressionMatchIterator object is a forward only Java-like
506 iterator; it can be obtained by calling the
507 QRegularExpression::globalMatch() function. A new
508 QRegularExpressionMatchIterator will be positioned before the first result.
509 You can then call the hasNext() function to check if there are more
510 results available; if so, the next() function will return the next
511 result and advance the iterator.
512
513 Each result is a QRegularExpressionMatch object holding all the information
514 for that result (including captured substrings).
515
516 For instance:
517
518 \snippet code/src_corelib_text_qregularexpression.cpp 30
519
520 Moreover, QRegularExpressionMatchIterator offers a peekNext() function
521 to get the next result \e{without} advancing the iterator.
522
523 Starting with Qt 6.0, it is also possible to simply use the result of
524 QRegularExpression::globalMatch in a range-based for loop, for instance
525 like this:
526
527 \snippet code/src_corelib_text_qregularexpression.cpp 34
528
529 You can retrieve the QRegularExpression object the subject string was
530 matched against by calling the regularExpression() function; the
531 match type and the match options are available as well by calling
532 the matchType() and the matchOptions() respectively.
533
534 Please refer to the QRegularExpression documentation for more information
535 about the Qt regular expression classes.
536
537 \sa QRegularExpression, QRegularExpressionMatch
538*/
539
540
541/*!
542 \enum QRegularExpression::PatternOption
543
544 The PatternOption enum defines modifiers to the way the pattern string
545 should be interpreted, and therefore the way the pattern matches against a
546 subject string.
547
548 \value NoPatternOption
549 No pattern options are set.
550
551 \value CaseInsensitiveOption
552 The pattern should match against the subject string in a case
553 insensitive way. This option corresponds to the /i modifier in Perl
554 regular expressions.
555
556 \value DotMatchesEverythingOption
557 The dot metacharacter (\c{.}) in the pattern string is allowed to match
558 any character in the subject string, including newlines (normally, the
559 dot does not match newlines). This option corresponds to the \c{/s}
560 modifier in Perl regular expressions.
561
562 \value MultilineOption
563 The caret (\c{^}) and the dollar (\c{$}) metacharacters in the pattern
564 string are allowed to match, respectively, immediately after and
565 immediately before any newline in the subject string, as well as at the
566 very beginning and at the very end of the subject string. This option
567 corresponds to the \c{/m} modifier in Perl regular expressions.
568
569 \value ExtendedPatternSyntaxOption
570 Any whitespace in the pattern string which is not escaped and outside a
571 character class is ignored. Moreover, an unescaped sharp (\b{#})
572 outside a character class causes all the following characters, until
573 the first newline (included), to be ignored. This can be used to
574 increase the readability of a pattern string as well as put comments
575 inside regular expressions; this is particularly useful if the pattern
576 string is loaded from a file or written by the user, because in C++
577 code it is always possible to use the rules for string literals to put
578 comments outside the pattern string. This option corresponds to the \c{/x}
579 modifier in Perl regular expressions.
580
581 \value InvertedGreedinessOption
582 The greediness of the quantifiers is inverted: \c{*}, \c{+}, \c{?},
583 \c{{m,n}}, etc. become lazy, while their lazy versions (\c{*?},
584 \c{+?}, \c{??}, \c{{m,n}?}, etc.) become greedy. There is no equivalent
585 for this option in Perl regular expressions.
586
587 \value DontCaptureOption
588 The non-named capturing groups do not capture substrings; named
589 capturing groups still work as intended, as well as the implicit
590 capturing group number 0 corresponding to the entire match. There is no
591 equivalent for this option in Perl regular expressions.
592
593 \value UseUnicodePropertiesOption
594 The meaning of the \c{\w}, \c{\d}, etc., character classes, as well as
595 the meaning of their counterparts (\c{\W}, \c{\D}, etc.), is changed
596 from matching ASCII characters only to matching any character with the
597 corresponding Unicode property. For instance, \c{\d} is changed to
598 match any character with the Unicode Nd (decimal digit) property;
599 \c{\w} to match any character with either the Unicode L (letter) or N
600 (digit) property, plus underscore, and so on. This option corresponds
601 to the \c{/u} modifier in Perl regular expressions.
602*/
603
604/*!
605 \enum QRegularExpression::MatchType
606
607 The MatchType enum defines the type of the match that should be attempted
608 against the subject string.
609
610 \value NormalMatch
611 A normal match is done.
612
613 \value PartialPreferCompleteMatch
614 The pattern string is matched partially against the subject string. If
615 a partial match is found, then it is recorded, and other matching
616 alternatives are tried as usual. If a complete match is then found,
617 then it's preferred to the partial match; in this case only the
618 complete match is reported. If instead no complete match is found (but
619 only the partial one), then the partial one is reported.
620
621 \value PartialPreferFirstMatch
622 The pattern string is matched partially against the subject string. If
623 a partial match is found, then matching stops and the partial match is
624 reported. In this case, other matching alternatives (potentially
625 leading to a complete match) are not tried. Moreover, this match type
626 assumes that the subject string only a substring of a larger text, and
627 that (in this text) there are other characters beyond the end of the
628 subject string. This can lead to surprising results; see the discussion
629 in the \l{partial matching} section for more details.
630
631 \value NoMatch
632 No matching is done. This value is returned as the match type by a
633 default constructed QRegularExpressionMatch or
634 QRegularExpressionMatchIterator. Using this match type is not very
635 useful for the user, as no matching ever happens. This enum value
636 has been introduced in Qt 5.1.
637*/
638
639/*!
640 \enum QRegularExpression::MatchOption
641
642 \value NoMatchOption
643 No match options are set.
644
645 \value AnchoredMatchOption
646 Use AnchorAtOffsetMatchOption instead.
647
648 \value AnchorAtOffsetMatchOption
649 The match is constrained to start exactly at the offset passed to
650 match() in order to be successful, even if the pattern string does not
651 contain any metacharacter that anchors the match at that point.
652 Note that passing this option does not anchor the end of the match
653 to the end of the subject; if you want to fully anchor a regular
654 expression, use anchoredPattern().
655 This enum value has been introduced in Qt 6.0.
656
657 \value DontCheckSubjectStringMatchOption
658 The subject string is not checked for UTF-16 validity before
659 attempting a match. Use this option with extreme caution, as
660 attempting to match an invalid string may crash the program and/or
661 constitute a security issue. This enum value has been introduced in
662 Qt 5.4.
663*/
664
665/*!
666 \internal
667*/
668static int convertToPcreOptions(QRegularExpression::PatternOptions patternOptions)
669{
670 int options = 0;
671
672 if (patternOptions & QRegularExpression::CaseInsensitiveOption)
673 options |= PCRE2_CASELESS;
674 if (patternOptions & QRegularExpression::DotMatchesEverythingOption)
675 options |= PCRE2_DOTALL;
676 if (patternOptions & QRegularExpression::MultilineOption)
677 options |= PCRE2_MULTILINE;
678 if (patternOptions & QRegularExpression::ExtendedPatternSyntaxOption)
679 options |= PCRE2_EXTENDED;
680 if (patternOptions & QRegularExpression::InvertedGreedinessOption)
681 options |= PCRE2_UNGREEDY;
682 if (patternOptions & QRegularExpression::DontCaptureOption)
683 options |= PCRE2_NO_AUTO_CAPTURE;
684 if (patternOptions & QRegularExpression::UseUnicodePropertiesOption)
685 options |= PCRE2_UCP;
686
687 return options;
688}
689
690/*!
691 \internal
692*/
693static int convertToPcreOptions(QRegularExpression::MatchOptions matchOptions)
694{
695 int options = 0;
696
697 if (matchOptions & QRegularExpression::AnchorAtOffsetMatchOption)
698 options |= PCRE2_ANCHORED;
699 if (matchOptions & QRegularExpression::DontCheckSubjectStringMatchOption)
700 options |= PCRE2_NO_UTF_CHECK;
701
702 return options;
703}
704
705struct QRegularExpressionPrivate : QSharedData
706{
707 QRegularExpressionPrivate();
708 ~QRegularExpressionPrivate();
709 QRegularExpressionPrivate(const QRegularExpressionPrivate &other);
710
711 void cleanCompiledPattern();
712 void compilePattern();
713 void getPatternInfo();
714 void optimizePattern();
715
716 enum CheckSubjectStringOption {
717 CheckSubjectString,
718 DontCheckSubjectString
719 };
720
721 void doMatch(QRegularExpressionMatchPrivate *priv,
722 qsizetype offset,
723 CheckSubjectStringOption checkSubjectStringOption = CheckSubjectString,
724 const QRegularExpressionMatchPrivate *previous = nullptr) const;
725
726 int captureIndexForName(QAnyStringView name) const;
727
728 // sizeof(QSharedData) == 4, so start our members with an enum
729 QRegularExpression::PatternOptions patternOptions;
730 QString pattern;
731
732 // *All* of the following members are managed while holding this mutex,
733 // except for isDirty which is set to true by QRegularExpression setters
734 // (right after a detach happened).
735 mutable QMutex mutex;
736
737 // The PCRE code pointer is reference-counted by the QRegularExpressionPrivate
738 // objects themselves; when the private is copied (i.e. a detach happened)
739 // it is set to nullptr
740 pcre2_code_16 *compiledPattern;
741 int errorCode;
742 qsizetype errorOffset;
743 int capturingCount;
744 bool usingCrLfNewlines;
745 bool isDirty;
746};
747
748struct QRegularExpressionMatchPrivate : QSharedData
749{
750 QRegularExpressionMatchPrivate(const QRegularExpression &re,
751 const QString &subjectStorage,
752 QStringView subject,
753 QRegularExpression::MatchType matchType,
754 QRegularExpression::MatchOptions matchOptions);
755
756 QRegularExpressionMatch nextMatch() const;
757
758 const QRegularExpression regularExpression;
759
760 // subject is what we match upon. If we've been asked to match over
761 // a QString, then subjectStorage is a copy of that string
762 // (so that it's kept alive by us)
763 const QString subjectStorage;
764 const QStringView subject;
765
766 const QRegularExpression::MatchType matchType;
767 const QRegularExpression::MatchOptions matchOptions;
768
769 // the capturedOffsets vector contains pairs of (start, end) positions
770 // for each captured substring
771 QList<qsizetype> capturedOffsets;
772
773 int capturedCount = 0;
774
775 bool hasMatch = false;
776 bool hasPartialMatch = false;
777 bool isValid = false;
778};
779
780struct QRegularExpressionMatchIteratorPrivate : QSharedData
781{
782 QRegularExpressionMatchIteratorPrivate(const QRegularExpression &re,
783 QRegularExpression::MatchType matchType,
784 QRegularExpression::MatchOptions matchOptions,
785 const QRegularExpressionMatch &next);
786
787 bool hasNext() const;
788 QRegularExpressionMatch next;
789 const QRegularExpression regularExpression;
790 const QRegularExpression::MatchType matchType;
791 const QRegularExpression::MatchOptions matchOptions;
792};
793
794/*!
795 \internal
796
797 Used to centralize the warning about using an invalid QRegularExpression.
798 In case the pattern is an illegal UTF-16 string, we can't pass print it
799 (pass it to qUtf16Printable, etc.), so we need to check for that.
800*/
801Q_DECL_COLD_FUNCTION
802void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *where)
803{
804 if (pattern.isValidUtf16()) {
805 qWarning(msg: "%s(): called on an invalid QRegularExpression object "
806 "(pattern is '%ls')", where, qUtf16Printable(pattern));
807 } else {
808 qWarning(msg: "%s(): called on an invalid QRegularExpression object", where);
809 }
810}
811
812/*!
813 \internal
814*/
815QRegularExpression::QRegularExpression(QRegularExpressionPrivate &dd)
816 : d(&dd)
817{
818}
819
820/*!
821 \internal
822*/
823QRegularExpressionPrivate::QRegularExpressionPrivate()
824 : QSharedData(),
825 patternOptions(),
826 pattern(),
827 mutex(),
828 compiledPattern(nullptr),
829 errorCode(0),
830 errorOffset(-1),
831 capturingCount(0),
832 usingCrLfNewlines(false),
833 isDirty(true)
834{
835}
836
837/*!
838 \internal
839*/
840QRegularExpressionPrivate::~QRegularExpressionPrivate()
841{
842 cleanCompiledPattern();
843}
844
845/*!
846 \internal
847
848 Copies the private, which means copying only the pattern and the pattern
849 options. The compiledPattern pointer is NOT copied (we
850 do not own it any more), and in general all the members set when
851 compiling a pattern are set to default values. isDirty is set back to true
852 so that the pattern has to be recompiled again.
853*/
854QRegularExpressionPrivate::QRegularExpressionPrivate(const QRegularExpressionPrivate &other)
855 : QSharedData(other),
856 patternOptions(other.patternOptions),
857 pattern(other.pattern),
858 mutex(),
859 compiledPattern(nullptr),
860 errorCode(0),
861 errorOffset(-1),
862 capturingCount(0),
863 usingCrLfNewlines(false),
864 isDirty(true)
865{
866}
867
868/*!
869 \internal
870*/
871void QRegularExpressionPrivate::cleanCompiledPattern()
872{
873 pcre2_code_free_16(compiledPattern);
874 compiledPattern = nullptr;
875 errorCode = 0;
876 errorOffset = -1;
877 capturingCount = 0;
878 usingCrLfNewlines = false;
879}
880
881/*!
882 \internal
883*/
884void QRegularExpressionPrivate::compilePattern()
885{
886 const QMutexLocker lock(&mutex);
887
888 if (!isDirty)
889 return;
890
891 isDirty = false;
892 cleanCompiledPattern();
893
894 int options = convertToPcreOptions(patternOptions);
895 options |= PCRE2_UTF;
896
897 PCRE2_SIZE patternErrorOffset;
898 compiledPattern = pcre2_compile_16(reinterpret_cast<PCRE2_SPTR16>(pattern.constData()),
899 pattern.size(),
900 options,
901 &errorCode,
902 &patternErrorOffset,
903 nullptr);
904
905 if (!compiledPattern) {
906 errorOffset = qsizetype(patternErrorOffset);
907 return;
908 } else {
909 // ignore whatever PCRE2 wrote into errorCode -- leave it to 0 to mean "no error"
910 errorCode = 0;
911 }
912
913 optimizePattern();
914 getPatternInfo();
915}
916
917/*!
918 \internal
919*/
920void QRegularExpressionPrivate::getPatternInfo()
921{
922 Q_ASSERT(compiledPattern);
923
924 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_CAPTURECOUNT, &capturingCount);
925
926 // detect the settings for the newline
927 unsigned int patternNewlineSetting;
928 if (pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NEWLINE, &patternNewlineSetting) != 0) {
929 // no option was specified in the regexp, grab PCRE build defaults
930 pcre2_config_16(PCRE2_CONFIG_NEWLINE, &patternNewlineSetting);
931 }
932
933 usingCrLfNewlines = (patternNewlineSetting == PCRE2_NEWLINE_CRLF) ||
934 (patternNewlineSetting == PCRE2_NEWLINE_ANY) ||
935 (patternNewlineSetting == PCRE2_NEWLINE_ANYCRLF);
936
937 unsigned int hasJOptionChanged;
938 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_JCHANGED, &hasJOptionChanged);
939 if (Q_UNLIKELY(hasJOptionChanged)) {
940 qWarning(msg: "QRegularExpressionPrivate::getPatternInfo(): the pattern '%ls'\n is using the (?J) option; duplicate capturing group names are not supported by Qt",
941 qUtf16Printable(pattern));
942 }
943}
944
945
946/*
947 Simple "smartpointer" wrapper around a pcre2_jit_stack_16, to be used with
948 QThreadStorage.
949*/
950namespace {
951struct PcreJitStackFree
952{
953 void operator()(pcre2_jit_stack_16 *stack)
954 {
955 if (stack)
956 pcre2_jit_stack_free_16(stack);
957 }
958};
959Q_CONSTINIT static thread_local std::unique_ptr<pcre2_jit_stack_16, PcreJitStackFree> jitStacks;
960}
961
962/*!
963 \internal
964*/
965static pcre2_jit_stack_16 *qtPcreCallback(void *)
966{
967 return jitStacks.get();
968}
969
970/*!
971 \internal
972*/
973static bool isJitEnabled()
974{
975 QByteArray jitEnvironment = qgetenv(varName: "QT_ENABLE_REGEXP_JIT");
976 if (!jitEnvironment.isEmpty()) {
977 bool ok;
978 int enableJit = jitEnvironment.toInt(ok: &ok);
979 return ok ? (enableJit != 0) : true;
980 }
981
982#ifdef QT_DEBUG
983 return false;
984#elif defined(Q_OS_MACOS)
985 return !qt_mac_runningUnderRosetta();
986#else
987 return true;
988#endif
989}
990
991/*!
992 \internal
993
994 The purpose of the function is to call pcre2_jit_compile_16, which
995 JIT-compiles the pattern.
996
997 It gets called when a pattern is recompiled by us (in compilePattern()),
998 under mutex protection.
999*/
1000void QRegularExpressionPrivate::optimizePattern()
1001{
1002 Q_ASSERT(compiledPattern);
1003
1004 static const bool enableJit = isJitEnabled();
1005
1006 if (!enableJit)
1007 return;
1008
1009 pcre2_jit_compile_16(compiledPattern, PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_PARTIAL_HARD);
1010}
1011
1012/*!
1013 \internal
1014
1015 Returns the capturing group number for the given name. Duplicated names for
1016 capturing groups are not supported.
1017*/
1018int QRegularExpressionPrivate::captureIndexForName(QAnyStringView name) const
1019{
1020 Q_ASSERT(!name.isEmpty());
1021
1022 if (!compiledPattern)
1023 return -1;
1024
1025 // See the other usages of pcre2_pattern_info_16 for more details about this
1026 PCRE2_SPTR16 *namedCapturingTable;
1027 unsigned int namedCapturingTableEntryCount;
1028 unsigned int namedCapturingTableEntrySize;
1029
1030 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
1031 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
1032 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
1033
1034 for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
1035 const auto currentNamedCapturingTableRow =
1036 reinterpret_cast<const char16_t *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
1037
1038 if (name == (currentNamedCapturingTableRow + 1)) {
1039 const int index = *currentNamedCapturingTableRow;
1040 return index;
1041 }
1042 }
1043
1044 return -1;
1045}
1046
1047/*!
1048 \internal
1049
1050 This is a simple wrapper for pcre2_match_16 for handling the case in which the
1051 JIT runs out of memory. In that case, we allocate a thread-local JIT stack
1052 and re-run pcre2_match_16.
1053*/
1054static int safe_pcre2_match_16(const pcre2_code_16 *code,
1055 PCRE2_SPTR16 subject, qsizetype length,
1056 qsizetype startOffset, int options,
1057 pcre2_match_data_16 *matchData,
1058 pcre2_match_context_16 *matchContext)
1059{
1060 int result = pcre2_match_16(code, subject, length,
1061 startOffset, options, matchData, matchContext);
1062
1063 if (result == PCRE2_ERROR_JIT_STACKLIMIT && !jitStacks) {
1064 // The default JIT stack size in PCRE is 32K,
1065 // we allocate from 32K up to 512K.
1066 jitStacks.reset(p: pcre2_jit_stack_create_16(32 * 1024, 512 * 1024, NULL));
1067
1068 result = pcre2_match_16(code, subject, length,
1069 startOffset, options, matchData, matchContext);
1070 }
1071
1072 return result;
1073}
1074
1075/*!
1076 \internal
1077
1078 Performs a match on the subject string view held by \a priv. The
1079 match will be of type priv->matchType and using the options
1080 priv->matchOptions; the matching \a offset is relative the
1081 substring, and if negative, it's taken as an offset from the end of
1082 the substring.
1083
1084 It also advances a match if a previous result is given as \a
1085 previous. The subject string goes a Unicode validity check if
1086 \a checkSubjectString is CheckSubjectString and the match options don't
1087 include DontCheckSubjectStringMatchOption (PCRE doesn't like illegal
1088 UTF-16 sequences).
1089
1090 \a priv is modified to hold the results of the match.
1091
1092 Advancing a match is a tricky algorithm. If the previous match matched a
1093 non-empty string, we just do an ordinary match at the offset position.
1094
1095 If the previous match matched an empty string, then an anchored, non-empty
1096 match is attempted at the offset position. If that succeeds, then we got
1097 the next match and we can return it. Otherwise, we advance by 1 position
1098 (which can be one or two code units in UTF-16!) and reattempt a "normal"
1099 match. We also have the problem of detecting the current newline format: if
1100 the new advanced offset is pointing to the beginning of a CRLF sequence, we
1101 must advance over it.
1102*/
1103void QRegularExpressionPrivate::doMatch(QRegularExpressionMatchPrivate *priv,
1104 qsizetype offset,
1105 CheckSubjectStringOption checkSubjectStringOption,
1106 const QRegularExpressionMatchPrivate *previous) const
1107{
1108 Q_ASSERT(priv);
1109 Q_ASSERT(priv != previous);
1110
1111 const qsizetype subjectLength = priv->subject.size();
1112
1113 if (offset < 0)
1114 offset += subjectLength;
1115
1116 if (offset < 0 || offset > subjectLength)
1117 return;
1118
1119 if (Q_UNLIKELY(!compiledPattern)) {
1120 qtWarnAboutInvalidRegularExpression(pattern, where: "QRegularExpressionPrivate::doMatch");
1121 return;
1122 }
1123
1124 // skip doing the actual matching if NoMatch type was requested
1125 if (priv->matchType == QRegularExpression::NoMatch) {
1126 priv->isValid = true;
1127 return;
1128 }
1129
1130 int pcreOptions = convertToPcreOptions(matchOptions: priv->matchOptions);
1131
1132 if (priv->matchType == QRegularExpression::PartialPreferCompleteMatch)
1133 pcreOptions |= PCRE2_PARTIAL_SOFT;
1134 else if (priv->matchType == QRegularExpression::PartialPreferFirstMatch)
1135 pcreOptions |= PCRE2_PARTIAL_HARD;
1136
1137 if (checkSubjectStringOption == DontCheckSubjectString)
1138 pcreOptions |= PCRE2_NO_UTF_CHECK;
1139
1140 bool previousMatchWasEmpty = false;
1141 if (previous && previous->hasMatch &&
1142 (previous->capturedOffsets.at(i: 0) == previous->capturedOffsets.at(i: 1))) {
1143 previousMatchWasEmpty = true;
1144 }
1145
1146 pcre2_match_context_16 *matchContext = pcre2_match_context_create_16(nullptr);
1147 pcre2_jit_stack_assign_16(matchContext, &qtPcreCallback, nullptr);
1148 pcre2_match_data_16 *matchData = pcre2_match_data_create_from_pattern_16(compiledPattern, nullptr);
1149
1150 // PCRE does not accept a null pointer as subject string, even if
1151 // its length is zero. We however allow it in input: a QStringView
1152 // subject may have data == nullptr. In this case, to keep PCRE
1153 // happy, pass a pointer to a dummy character.
1154 const char16_t dummySubject = 0;
1155 const char16_t * const subjectUtf16 = [&]()
1156 {
1157 const auto subjectUtf16 = priv->subject.utf16();
1158 if (subjectUtf16)
1159 return subjectUtf16;
1160 Q_ASSERT(subjectLength == 0);
1161 return &dummySubject;
1162 }();
1163
1164 int result;
1165
1166 if (!previousMatchWasEmpty) {
1167 result = safe_pcre2_match_16(code: compiledPattern,
1168 subject: reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), length: subjectLength,
1169 startOffset: offset, options: pcreOptions,
1170 matchData, matchContext);
1171 } else {
1172 result = safe_pcre2_match_16(code: compiledPattern,
1173 subject: reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), length: subjectLength,
1174 startOffset: offset, options: pcreOptions | PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED,
1175 matchData, matchContext);
1176
1177 if (result == PCRE2_ERROR_NOMATCH) {
1178 ++offset;
1179
1180 if (usingCrLfNewlines
1181 && offset < subjectLength
1182 && subjectUtf16[offset - 1] == u'\r'
1183 && subjectUtf16[offset] == u'\n') {
1184 ++offset;
1185 } else if (offset < subjectLength
1186 && QChar::isLowSurrogate(ucs4: subjectUtf16[offset])) {
1187 ++offset;
1188 }
1189
1190 result = safe_pcre2_match_16(code: compiledPattern,
1191 subject: reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), length: subjectLength,
1192 startOffset: offset, options: pcreOptions,
1193 matchData, matchContext);
1194 }
1195 }
1196
1197#ifdef QREGULAREXPRESSION_DEBUG
1198 qDebug() << "Matching" << pattern << "against" << subject
1199 << "offset" << offset
1200 << priv->matchType << priv->matchOptions << previousMatchWasEmpty
1201 << "result" << result;
1202#endif
1203
1204 // result == 0 means not enough space in captureOffsets; should never happen
1205 Q_ASSERT(result != 0);
1206
1207 if (result > 0) {
1208 // full match
1209 priv->isValid = true;
1210 priv->hasMatch = true;
1211 priv->capturedCount = result;
1212 priv->capturedOffsets.resize(size: result * 2);
1213 } else {
1214 // no match, partial match or error
1215 priv->hasPartialMatch = (result == PCRE2_ERROR_PARTIAL);
1216 priv->isValid = (result == PCRE2_ERROR_NOMATCH || result == PCRE2_ERROR_PARTIAL);
1217
1218 if (result == PCRE2_ERROR_PARTIAL) {
1219 // partial match:
1220 // leave the start and end capture offsets (i.e. cap(0))
1221 priv->capturedCount = 1;
1222 priv->capturedOffsets.resize(size: 2);
1223 } else {
1224 // no match or error
1225 priv->capturedCount = 0;
1226 priv->capturedOffsets.clear();
1227 }
1228 }
1229
1230 // copy the captured substrings offsets, if any
1231 if (priv->capturedCount) {
1232 PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_16(matchData);
1233 qsizetype *const capturedOffsets = priv->capturedOffsets.data();
1234
1235 // We rely on the fact that capturing groups that did not
1236 // capture anything have offset -1, but PCRE technically
1237 // returns "PCRE2_UNSET". Test that out, better safe than
1238 // sorry...
1239 static_assert(qsizetype(PCRE2_UNSET) == qsizetype(-1), "Internal error: PCRE2 changed its API");
1240
1241 for (int i = 0; i < priv->capturedCount * 2; ++i)
1242 capturedOffsets[i] = qsizetype(ovector[i]);
1243
1244 // For partial matches, PCRE2 and PCRE1 differ in behavior when lookbehinds
1245 // are involved. PCRE2 reports the real begin of the match and the maximum
1246 // used lookbehind as distinct information; PCRE1 instead automatically
1247 // adjusted ovector[0] to include the maximum lookbehind.
1248 //
1249 // For instance, given the pattern "\bstring\b", and the subject "a str":
1250 // * PCRE1 reports partial, capturing " str"
1251 // * PCRE2 reports partial, capturing "str" with a lookbehind of 1
1252 //
1253 // To keep behavior, emulate PCRE1 here.
1254 // (Eventually, we could expose the lookbehind info in a future patch.)
1255 if (result == PCRE2_ERROR_PARTIAL) {
1256 unsigned int maximumLookBehind;
1257 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_MAXLOOKBEHIND, &maximumLookBehind);
1258 capturedOffsets[0] -= maximumLookBehind;
1259 }
1260 }
1261
1262 pcre2_match_data_free_16(matchData);
1263 pcre2_match_context_free_16(matchContext);
1264}
1265
1266/*!
1267 \internal
1268*/
1269QRegularExpressionMatchPrivate::QRegularExpressionMatchPrivate(const QRegularExpression &re,
1270 const QString &subjectStorage,
1271 QStringView subject,
1272 QRegularExpression::MatchType matchType,
1273 QRegularExpression::MatchOptions matchOptions)
1274 : regularExpression(re),
1275 subjectStorage(subjectStorage),
1276 subject(subject),
1277 matchType(matchType),
1278 matchOptions(matchOptions)
1279{
1280}
1281
1282/*!
1283 \internal
1284*/
1285QRegularExpressionMatch QRegularExpressionMatchPrivate::nextMatch() const
1286{
1287 Q_ASSERT(isValid);
1288 Q_ASSERT(hasMatch || hasPartialMatch);
1289
1290 auto nextPrivate = new QRegularExpressionMatchPrivate(regularExpression,
1291 subjectStorage,
1292 subject,
1293 matchType,
1294 matchOptions);
1295
1296 // Note the DontCheckSubjectString passed for the check of the subject string:
1297 // if we're advancing a match on the same subject,
1298 // then that subject was already checked at least once (when this object
1299 // was created, or when the object that created this one was created, etc.)
1300 regularExpression.d->doMatch(priv: nextPrivate,
1301 offset: capturedOffsets.at(i: 1),
1302 checkSubjectStringOption: QRegularExpressionPrivate::DontCheckSubjectString,
1303 previous: this);
1304 return QRegularExpressionMatch(*nextPrivate);
1305}
1306
1307/*!
1308 \internal
1309*/
1310QRegularExpressionMatchIteratorPrivate::QRegularExpressionMatchIteratorPrivate(const QRegularExpression &re,
1311 QRegularExpression::MatchType matchType,
1312 QRegularExpression::MatchOptions matchOptions,
1313 const QRegularExpressionMatch &next)
1314 : next(next),
1315 regularExpression(re),
1316 matchType(matchType), matchOptions(matchOptions)
1317{
1318}
1319
1320/*!
1321 \internal
1322*/
1323bool QRegularExpressionMatchIteratorPrivate::hasNext() const
1324{
1325 return next.isValid() && (next.hasMatch() || next.hasPartialMatch());
1326}
1327
1328// PUBLIC API
1329
1330/*!
1331 Constructs a QRegularExpression object with an empty pattern and no pattern
1332 options.
1333
1334 \sa setPattern(), setPatternOptions()
1335*/
1336QRegularExpression::QRegularExpression()
1337 : d(new QRegularExpressionPrivate)
1338{
1339}
1340
1341/*!
1342 Constructs a QRegularExpression object using the given \a pattern as
1343 pattern and the \a options as the pattern options.
1344
1345 \sa setPattern(), setPatternOptions()
1346*/
1347QRegularExpression::QRegularExpression(const QString &pattern, PatternOptions options)
1348 : d(new QRegularExpressionPrivate)
1349{
1350 d->pattern = pattern;
1351 d->patternOptions = options;
1352}
1353
1354/*!
1355 Constructs a QRegularExpression object as a copy of \a re.
1356
1357 \sa operator=()
1358*/
1359QRegularExpression::QRegularExpression(const QRegularExpression &re) noexcept = default;
1360
1361/*!
1362 \fn QRegularExpression::QRegularExpression(QRegularExpression &&re)
1363
1364 \since 6.1
1365
1366 Constructs a QRegularExpression object by moving from \a re.
1367
1368 Note that a moved-from QRegularExpression can only be destroyed or
1369 assigned to. The effect of calling other functions than the destructor
1370 or one of the assignment operators is undefined.
1371
1372 \sa operator=()
1373*/
1374
1375/*!
1376 Destroys the QRegularExpression object.
1377*/
1378QRegularExpression::~QRegularExpression()
1379{
1380}
1381
1382QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QRegularExpressionPrivate)
1383
1384/*!
1385 Assigns the regular expression \a re to this object, and returns a reference
1386 to the copy. Both the pattern and the pattern options are copied.
1387*/
1388QRegularExpression &QRegularExpression::operator=(const QRegularExpression &re) noexcept = default;
1389
1390/*!
1391 \fn void QRegularExpression::swap(QRegularExpression &other)
1392 \memberswap{regular expression}
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] = QStringView(currentNamedCapturingTableRow + 1).toString();
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 \fn bool QRegularExpression::operator==(const QRegularExpression &lhs, const QRegularExpression &rhs) noexcept
1738
1739 Returns \c true if the \a lhs regular expression is equal to the \a rhs, or false
1740 otherwise. Two QRegularExpression objects are equal if they have
1741 the same pattern string and the same pattern options.
1742
1743 \sa operator!=()
1744*/
1745bool comparesEqual(const QRegularExpression &lhs,
1746 const QRegularExpression &rhs) noexcept
1747{
1748 return (lhs.d == rhs.d) ||
1749 (lhs.d->pattern == rhs.d->pattern && lhs.d->patternOptions == rhs.d->patternOptions);
1750}
1751/*!
1752 \fn QRegularExpression & QRegularExpression::operator=(QRegularExpression && re)
1753
1754 Move-assigns the regular expression \a re to this object, and returns a
1755 reference to the result. Both the pattern and the pattern options are copied.
1756
1757 Note that a moved-from QRegularExpression can only be destroyed or
1758 assigned to. The effect of calling other functions than the destructor
1759 or one of the assignment operators is undefined.
1760*/
1761
1762/*!
1763 \fn bool QRegularExpression::operator!=(const QRegularExpression &lhs, const QRegularExpression &rhs) noexcept
1764
1765 Returns \c true if the \a lhs regular expression is different from the \a rhs, or
1766 false otherwise.
1767
1768 \sa operator==()
1769*/
1770
1771/*!
1772 \since 5.6
1773 \relates QRegularExpression
1774
1775 Returns the hash value for \a key, using
1776 \a seed to seed the calculation.
1777*/
1778size_t qHash(const QRegularExpression &key, size_t seed) noexcept
1779{
1780 return qHashMulti(seed, args: key.d->pattern, args: key.d->patternOptions);
1781}
1782
1783/*!
1784 \fn QString QRegularExpression::escape(const QString &str)
1785 \overload
1786*/
1787
1788/*!
1789 \since 5.15
1790
1791 Escapes all characters of \a str so that they no longer have any special
1792 meaning when used as a regular expression pattern string, and returns
1793 the escaped string. For instance:
1794
1795 \snippet code/src_corelib_text_qregularexpression.cpp 26
1796
1797 This is very convenient in order to build patterns from arbitrary strings:
1798
1799 \snippet code/src_corelib_text_qregularexpression.cpp 27
1800
1801 \note This function implements Perl's quotemeta algorithm and escapes with
1802 a backslash all characters in \a str, except for the characters in the
1803 \c{[A-Z]}, \c{[a-z]} and \c{[0-9]} ranges, as well as the underscore
1804 (\c{_}) character. The only difference with Perl is that a literal NUL
1805 inside \a str is escaped with the sequence \c{"\\0"} (backslash +
1806 \c{'0'}), instead of \c{"\\\0"} (backslash + \c{NUL}).
1807*/
1808QString QRegularExpression::escape(QStringView str)
1809{
1810 QString result;
1811 const qsizetype count = str.size();
1812 result.reserve(asize: count * 2);
1813
1814 // everything but [a-zA-Z0-9_] gets escaped,
1815 // cf. perldoc -f quotemeta
1816 for (qsizetype i = 0; i < count; ++i) {
1817 const QChar current = str.at(n: i);
1818
1819 if (current == QChar::Null) {
1820 // unlike Perl, a literal NUL must be escaped with
1821 // "\\0" (backslash + 0) and not "\\\0" (backslash + NUL),
1822 // because pcre16_compile uses a NUL-terminated string
1823 result.append(c: u'\\');
1824 result.append(c: u'0');
1825 } else if ((current < u'a' || current > u'z') &&
1826 (current < u'A' || current > u'Z') &&
1827 (current < u'0' || current > u'9') &&
1828 current != u'_') {
1829 result.append(c: u'\\');
1830 result.append(c: current);
1831 if (current.isHighSurrogate() && i < (count - 1))
1832 result.append(c: str.at(n: ++i));
1833 } else {
1834 result.append(c: current);
1835 }
1836 }
1837
1838 result.squeeze();
1839 return result;
1840}
1841
1842/*!
1843 \since 5.12
1844 \fn QString QRegularExpression::wildcardToRegularExpression(const QString &pattern, WildcardConversionOptions options)
1845 \overload
1846*/
1847
1848/*!
1849 \since 6.0
1850 \enum QRegularExpression::WildcardConversionOption
1851
1852 The WildcardConversionOption enum defines modifiers to the way a wildcard glob
1853 pattern gets converted to a regular expression pattern.
1854
1855 \value DefaultWildcardConversion
1856 No conversion options are set.
1857
1858 \value UnanchoredWildcardConversion
1859 The conversion will not anchor the pattern. This allows for partial string matches of
1860 wildcard expressions.
1861
1862 \value [since 6.6] NonPathWildcardConversion
1863 The conversion will \e{not} interpret the pattern as filepath globbing.
1864
1865 \sa QRegularExpression::wildcardToRegularExpression
1866*/
1867
1868/*!
1869 \since 5.15
1870
1871 Returns a regular expression representation of the given glob \a pattern.
1872
1873 There are two transformations possible, one that targets file path
1874 globbing, and another one which is more generic.
1875
1876 By default, the transformation is targeting file path globbing,
1877 which means in particular that path separators receive special
1878 treatment. This implies that it is not just a basic translation
1879 from "*" to ".*" and similar.
1880
1881 \snippet code/src_corelib_text_qregularexpression.cpp 31
1882
1883 The more generic globbing transformation is available by passing
1884 \c NonPathWildcardConversion in the conversion \a options.
1885
1886 This implementation follows closely the definition
1887 of wildcard for glob patterns:
1888 \table
1889 \row \li \b{c}
1890 \li Any character represents itself apart from those mentioned
1891 below. Thus \b{c} matches the character \e c.
1892 \row \li \b{?}
1893 \li Matches any single character, except for a path separator
1894 (in case file path globbing has been selected). It is the
1895 same as b{.} in full regexps.
1896 \row \li \b{*}
1897 \li Matches zero or more of any characters, except for path
1898 separators (in case file path globbing has been selected). It is the
1899 same as \b{.*} in full regexps.
1900 \row \li \b{[abc]}
1901 \li Matches one character given in the bracket.
1902 \row \li \b{[a-c]}
1903 \li Matches one character from the range given in the bracket.
1904 \row \li \b{[!abc]}
1905 \li Matches one character that is not given in the bracket. It is the
1906 same as \b{[^abc]} in full regexp.
1907 \row \li \b{[!a-c]}
1908 \li Matches one character that is not from the range given in the
1909 bracket. It is the same as \b{[^a-c]} in full regexp.
1910 \endtable
1911
1912 \note For historical reasons, a backslash (\\) character is \e not
1913 an escape char in this context. In order to match one of the
1914 special characters, place it in square brackets (for example,
1915 \c{[?]}).
1916
1917 More information about the implementation can be found in:
1918 \list
1919 \li \l {https://en.wikipedia.org/wiki/Glob_(programming)} {The Wikipedia Glob article}
1920 \li \c {man 7 glob}
1921 \endlist
1922
1923 By default, the returned regular expression is fully anchored. In other
1924 words, there is no need of calling anchoredPattern() again on the
1925 result. To get a regular expression that is not anchored, pass
1926 UnanchoredWildcardConversion in the conversion \a options.
1927
1928 \sa escape()
1929*/
1930QString QRegularExpression::wildcardToRegularExpression(QStringView pattern, WildcardConversionOptions options)
1931{
1932 const qsizetype wclen = pattern.size();
1933 QString rx;
1934 rx.reserve(asize: wclen + wclen / 16);
1935 qsizetype i = 0;
1936 const QChar *wc = pattern.data();
1937
1938 struct GlobSettings {
1939 char16_t nativePathSeparator;
1940 QStringView starEscape;
1941 QStringView questionMarkEscape;
1942 };
1943
1944 const GlobSettings settings = [options]() {
1945 if (options.testFlag(flag: NonPathWildcardConversion)) {
1946 // using [\d\D] to mean "match everything";
1947 // dot doesn't match newlines, unless in /s mode
1948 return GlobSettings{ .nativePathSeparator: u'\0', .starEscape: u"[\\d\\D]*", .questionMarkEscape: u"[\\d\\D]" };
1949 } else {
1950#ifdef Q_OS_WIN
1951 return GlobSettings{ u'\\', u"[^/\\\\]*", u"[^/\\\\]" };
1952#else
1953 return GlobSettings{ .nativePathSeparator: u'/', .starEscape: u"[^/]*", .questionMarkEscape: u"[^/]" };
1954#endif
1955 }
1956 }();
1957
1958 while (i < wclen) {
1959 const QChar c = wc[i++];
1960 switch (c.unicode()) {
1961 case '*':
1962 rx += settings.starEscape;
1963 // Coalesce sequences of *
1964 while (i < wclen && wc[i] == u'*')
1965 ++i;
1966 break;
1967 case '?':
1968 rx += settings.questionMarkEscape;
1969 break;
1970 // When not using filepath globbing: \ is escaped, / is itself
1971 // When using filepath globbing:
1972 // * Unix: \ gets escaped. / is itself
1973 // * Windows: \ and / can match each other -- they become [/\\] in regexp
1974 case '\\':
1975#ifdef Q_OS_WIN
1976 if (options.testFlag(NonPathWildcardConversion))
1977 rx += u"\\\\";
1978 else
1979 rx += u"[/\\\\]";
1980 break;
1981 case '/':
1982 if (options.testFlag(NonPathWildcardConversion))
1983 rx += u'/';
1984 else
1985 rx += u"[/\\\\]";
1986 break;
1987#endif
1988 case '$':
1989 case '(':
1990 case ')':
1991 case '+':
1992 case '.':
1993 case '^':
1994 case '{':
1995 case '|':
1996 case '}':
1997 rx += u'\\';
1998 rx += c;
1999 break;
2000 case '[':
2001 rx += c;
2002 // Support for the [!abc] or [!a-c] syntax
2003 if (i < wclen) {
2004 if (wc[i] == u'!') {
2005 rx += u'^';
2006 ++i;
2007 }
2008
2009 if (i < wclen && wc[i] == u']')
2010 rx += wc[i++];
2011
2012 while (i < wclen && wc[i] != u']') {
2013 if (!options.testFlag(flag: NonPathWildcardConversion)) {
2014 // The '/' appearing in a character class invalidates the
2015 // regular expression parsing. It also concerns '\\' on
2016 // Windows OS types.
2017 if (wc[i] == u'/' || wc[i] == settings.nativePathSeparator)
2018 return rx;
2019 }
2020 if (wc[i] == u'\\')
2021 rx += u'\\';
2022 rx += wc[i++];
2023 }
2024 }
2025 break;
2026 default:
2027 rx += c;
2028 break;
2029 }
2030 }
2031
2032 if (!(options & UnanchoredWildcardConversion))
2033 rx = anchoredPattern(expression: rx);
2034
2035 return rx;
2036}
2037
2038/*!
2039 \since 6.0
2040 Returns a regular expression of the glob pattern \a pattern. The regular expression
2041 will be case sensitive if \a cs is \l{Qt::CaseSensitive}, and converted according to
2042 \a options.
2043
2044 Equivalent to
2045 \code
2046 auto reOptions = cs == Qt::CaseSensitive ? QRegularExpression::NoPatternOption :
2047 QRegularExpression::CaseInsensitiveOption;
2048 return QRegularExpression(wildcardToRegularExpression(str, options), reOptions);
2049 \endcode
2050*/
2051QRegularExpression QRegularExpression::fromWildcard(QStringView pattern, Qt::CaseSensitivity cs,
2052 WildcardConversionOptions options)
2053{
2054 auto reOptions = cs == Qt::CaseSensitive ? QRegularExpression::NoPatternOption :
2055 QRegularExpression::CaseInsensitiveOption;
2056 return QRegularExpression(wildcardToRegularExpression(pattern, options), reOptions);
2057}
2058
2059/*!
2060 \fn QRegularExpression::anchoredPattern(const QString &expression)
2061 \since 5.12
2062 \overload
2063*/
2064
2065/*!
2066 \since 5.15
2067
2068 Returns the \a expression wrapped between the \c{\A} and \c{\z} anchors to
2069 be used for exact matching.
2070*/
2071QString QRegularExpression::anchoredPattern(QStringView expression)
2072{
2073 return QString()
2074 + "\\A(?:"_L1
2075 + expression
2076 + ")\\z"_L1;
2077}
2078
2079/*!
2080 \since 5.1
2081
2082 Constructs a valid, empty QRegularExpressionMatch object. The regular
2083 expression is set to a default-constructed one; the match type to
2084 QRegularExpression::NoMatch and the match options to
2085 QRegularExpression::NoMatchOption.
2086
2087 The object will report no match through the hasMatch() and the
2088 hasPartialMatch() member functions.
2089*/
2090QRegularExpressionMatch::QRegularExpressionMatch()
2091 : d(new QRegularExpressionMatchPrivate(QRegularExpression(),
2092 QString(),
2093 QStringView(),
2094 QRegularExpression::NoMatch,
2095 QRegularExpression::NoMatchOption))
2096{
2097 d->isValid = true;
2098}
2099
2100/*!
2101 Destroys the match result.
2102*/
2103QRegularExpressionMatch::~QRegularExpressionMatch()
2104{
2105}
2106
2107QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QRegularExpressionMatchPrivate)
2108
2109/*!
2110 Constructs a match result by copying the result of the given \a match.
2111
2112 \sa operator=()
2113*/
2114QRegularExpressionMatch::QRegularExpressionMatch(const QRegularExpressionMatch &match)
2115 : d(match.d)
2116{
2117}
2118
2119/*!
2120 \fn QRegularExpressionMatch::QRegularExpressionMatch(QRegularExpressionMatch &&match)
2121
2122 \since 6.1
2123
2124 Constructs a match result by moving the result from the given \a match.
2125
2126 Note that a moved-from QRegularExpressionMatch can only be destroyed or
2127 assigned to. The effect of calling other functions than the destructor
2128 or one of the assignment operators is undefined.
2129
2130 \sa operator=()
2131*/
2132
2133/*!
2134 Assigns the match result \a match to this object, and returns a reference
2135 to the copy.
2136*/
2137QRegularExpressionMatch &QRegularExpressionMatch::operator=(const QRegularExpressionMatch &match)
2138{
2139 d = match.d;
2140 return *this;
2141}
2142
2143/*!
2144 \fn QRegularExpressionMatch &QRegularExpressionMatch::operator=(QRegularExpressionMatch &&match)
2145
2146 Move-assigns the match result \a match to this object, and returns a
2147 reference to the result.
2148
2149 Note that a moved-from QRegularExpressionMatch can only be destroyed or
2150 assigned to. The effect of calling other functions than the destructor
2151 or one of the assignment operators is undefined.
2152*/
2153
2154/*!
2155 \fn void QRegularExpressionMatch::swap(QRegularExpressionMatch &other)
2156 \memberswap{match result}
2157*/
2158
2159/*!
2160 \internal
2161*/
2162QRegularExpressionMatch::QRegularExpressionMatch(QRegularExpressionMatchPrivate &dd)
2163 : d(&dd)
2164{
2165}
2166
2167/*!
2168 Returns the QRegularExpression object whose match() function returned this
2169 object.
2170
2171 \sa QRegularExpression::match(), matchType(), matchOptions()
2172*/
2173QRegularExpression QRegularExpressionMatch::regularExpression() const
2174{
2175 return d->regularExpression;
2176}
2177
2178
2179/*!
2180 Returns the match type that was used to get this QRegularExpressionMatch
2181 object, that is, the match type that was passed to
2182 QRegularExpression::match() or QRegularExpression::globalMatch().
2183
2184 \sa QRegularExpression::match(), regularExpression(), matchOptions()
2185*/
2186QRegularExpression::MatchType QRegularExpressionMatch::matchType() const
2187{
2188 return d->matchType;
2189}
2190
2191/*!
2192 Returns the match options that were used to get this
2193 QRegularExpressionMatch object, that is, the match options that were passed
2194 to QRegularExpression::match() or QRegularExpression::globalMatch().
2195
2196 \sa QRegularExpression::match(), regularExpression(), matchType()
2197*/
2198QRegularExpression::MatchOptions QRegularExpressionMatch::matchOptions() const
2199{
2200 return d->matchOptions;
2201}
2202
2203/*!
2204 Returns the index of the last capturing group that captured something,
2205 including the implicit capturing group 0. This can be used to extract all
2206 the substrings that were captured:
2207
2208 \snippet code/src_corelib_text_qregularexpression.cpp 28
2209
2210 Note that some of the capturing groups with an index less than
2211 lastCapturedIndex() could have not matched, and therefore captured nothing.
2212
2213 If the regular expression did not match, this function returns -1.
2214
2215 \sa hasCaptured(), captured(), capturedStart(), capturedEnd(), capturedLength()
2216*/
2217int QRegularExpressionMatch::lastCapturedIndex() const
2218{
2219 return d->capturedCount - 1;
2220}
2221
2222/*!
2223 \fn bool QRegularExpressionMatch::hasCaptured(QAnyStringView name) const
2224 \since 6.3
2225
2226 Returns true if the capturing group named \a name captured something
2227 in the subject string, and false otherwise (or if there is no
2228 capturing group called \a name).
2229
2230 \note Some capturing groups in a regular expression may not have
2231 captured anything even if the regular expression matched. This may
2232 happen, for instance, if a conditional operator is used in the
2233 pattern:
2234
2235 \snippet code/src_corelib_text_qregularexpression.cpp 36
2236
2237 Similarly, a capturing group may capture a substring of length 0;
2238 this function will return \c{true} for such a capturing group.
2239
2240 \note In Qt versions prior to 6.8, this function took QString or
2241 QStringView, not QAnyStringView.
2242
2243 \sa captured(), hasMatch()
2244*/
2245bool QRegularExpressionMatch::hasCaptured(QAnyStringView name) const
2246{
2247 const int nth = d->regularExpression.d->captureIndexForName(name);
2248 return hasCaptured(nth);
2249}
2250
2251/*!
2252 \since 6.3
2253
2254 Returns true if the \a nth capturing group captured something
2255 in the subject string, and false otherwise (or if there is no
2256 such capturing group).
2257
2258 \note The implicit capturing group number 0 captures the substring
2259 matched by the entire pattern.
2260
2261 \note Some capturing groups in a regular expression may not have
2262 captured anything even if the regular expression matched. This may
2263 happen, for instance, if a conditional operator is used in the
2264 pattern:
2265
2266 \snippet code/src_corelib_text_qregularexpression.cpp 36
2267
2268 Similarly, a capturing group may capture a substring of length 0;
2269 this function will return \c{true} for such a capturing group.
2270
2271 \sa captured(), lastCapturedIndex(), hasMatch()
2272*/
2273bool QRegularExpressionMatch::hasCaptured(int nth) const
2274{
2275 if (nth < 0 || nth > lastCapturedIndex())
2276 return false;
2277
2278 return d->capturedOffsets.at(i: nth * 2) != -1;
2279}
2280
2281/*!
2282 Returns the substring captured by the \a nth capturing group.
2283
2284 If the \a nth capturing group did not capture a string, or if there is no
2285 such capturing group, returns a null QString.
2286
2287 \note The implicit capturing group number 0 captures the substring matched
2288 by the entire pattern.
2289
2290 \sa capturedView(), lastCapturedIndex(), capturedStart(), capturedEnd(),
2291 capturedLength(), QString::isNull()
2292*/
2293QString QRegularExpressionMatch::captured(int nth) const
2294{
2295 return capturedView(nth).toString();
2296}
2297
2298/*!
2299 \since 5.10
2300
2301 Returns a view of the substring captured by the \a nth capturing group.
2302
2303 If the \a nth capturing group did not capture a string, or if there is no
2304 such capturing group, returns a null QStringView.
2305
2306 \note The implicit capturing group number 0 captures the substring matched
2307 by the entire pattern.
2308
2309 \sa captured(), lastCapturedIndex(), capturedStart(), capturedEnd(),
2310 capturedLength(), QStringView::isNull()
2311*/
2312QStringView QRegularExpressionMatch::capturedView(int nth) const
2313{
2314 if (!hasCaptured(nth))
2315 return QStringView();
2316
2317 qsizetype start = capturedStart(nth);
2318
2319 if (start == -1) // didn't capture
2320 return QStringView();
2321
2322 return d->subject.mid(pos: start, n: capturedLength(nth));
2323}
2324
2325/*!
2326 \since 5.10
2327
2328 Returns the substring captured by the capturing group named \a name.
2329
2330 If the named capturing group \a name did not capture a string, or if
2331 there is no capturing group named \a name, returns a null QString.
2332
2333 \note In Qt versions prior to 6.8, this function took QString or
2334 QStringView, not QAnyStringView.
2335
2336 \sa capturedView(), capturedStart(), capturedEnd(), capturedLength(),
2337 QString::isNull()
2338*/
2339QString QRegularExpressionMatch::captured(QAnyStringView name) const
2340{
2341 if (name.isEmpty()) {
2342 qWarning(msg: "QRegularExpressionMatch::captured: empty capturing group name passed");
2343 return QString();
2344 }
2345
2346 return capturedView(name).toString();
2347}
2348
2349/*!
2350 \since 5.10
2351
2352 Returns a view of the string captured by the capturing group named \a
2353 name.
2354
2355 If the named capturing group \a name did not capture a string, or if
2356 there is no capturing group named \a name, returns a null QStringView.
2357
2358 \note In Qt versions prior to 6.8, this function took QString or
2359 QStringView, not QAnyStringView.
2360
2361 \sa captured(), capturedStart(), capturedEnd(), capturedLength(),
2362 QStringView::isNull()
2363*/
2364QStringView QRegularExpressionMatch::capturedView(QAnyStringView 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/*!
2437 \since 5.10
2438
2439 Returns the offset inside the subject string corresponding to the starting
2440 position of the substring captured by the capturing group named \a name.
2441 If the capturing group named \a name did not capture a string or doesn't
2442 exist, returns -1.
2443
2444 \note In Qt versions prior to 6.8, this function took QString or
2445 QStringView, not QAnyStringView.
2446
2447 \sa capturedEnd(), capturedLength(), captured()
2448*/
2449qsizetype QRegularExpressionMatch::capturedStart(QAnyStringView name) const
2450{
2451 if (name.isEmpty()) {
2452 qWarning(msg: "QRegularExpressionMatch::capturedStart: empty capturing group name passed");
2453 return -1;
2454 }
2455 int nth = d->regularExpression.d->captureIndexForName(name);
2456 if (nth == -1)
2457 return -1;
2458 return capturedStart(nth);
2459}
2460
2461/*!
2462 \since 5.10
2463
2464 Returns the length of the substring captured by the capturing group named
2465 \a name.
2466
2467 \note This function returns 0 if the capturing group named \a name did not
2468 capture a string or doesn't exist.
2469
2470 \note In Qt versions prior to 6.8, this function took QString or
2471 QStringView, not QAnyStringView.
2472
2473 \sa capturedStart(), capturedEnd(), captured()
2474*/
2475qsizetype QRegularExpressionMatch::capturedLength(QAnyStringView name) const
2476{
2477 if (name.isEmpty()) {
2478 qWarning(msg: "QRegularExpressionMatch::capturedLength: empty capturing group name passed");
2479 return 0;
2480 }
2481 int nth = d->regularExpression.d->captureIndexForName(name);
2482 if (nth == -1)
2483 return 0;
2484 return capturedLength(nth);
2485}
2486
2487/*!
2488 \since 5.10
2489
2490 Returns the offset inside the subject string immediately after the ending
2491 position of the substring captured by the capturing group named \a name. If
2492 the capturing group named \a name did not capture a string or doesn't
2493 exist, returns -1.
2494
2495 \note In Qt versions prior to 6.8, this function took QString or
2496 QStringView, not QAnyStringView.
2497
2498 \sa capturedStart(), capturedLength(), captured()
2499*/
2500qsizetype QRegularExpressionMatch::capturedEnd(QAnyStringView name) const
2501{
2502 if (name.isEmpty()) {
2503 qWarning(msg: "QRegularExpressionMatch::capturedEnd: empty capturing group name passed");
2504 return -1;
2505 }
2506 int nth = d->regularExpression.d->captureIndexForName(name);
2507 if (nth == -1)
2508 return -1;
2509 return capturedEnd(nth);
2510}
2511
2512/*!
2513 Returns \c true if the regular expression matched against the subject string,
2514 or false otherwise.
2515
2516 \sa QRegularExpression::match(), hasPartialMatch()
2517*/
2518bool QRegularExpressionMatch::hasMatch() const
2519{
2520 return d->hasMatch;
2521}
2522
2523/*!
2524 Returns \c true if the regular expression partially matched against the
2525 subject string, or false otherwise.
2526
2527 \note Only a match that explicitly used the one of the partial match types
2528 can yield a partial match. Still, if such a match succeeds totally, this
2529 function will return false, while hasMatch() will return true.
2530
2531 \sa QRegularExpression::match(), QRegularExpression::MatchType, hasMatch()
2532*/
2533bool QRegularExpressionMatch::hasPartialMatch() const
2534{
2535 return d->hasPartialMatch;
2536}
2537
2538/*!
2539 Returns \c true if the match object was obtained as a result from the
2540 QRegularExpression::match() function invoked on a valid QRegularExpression
2541 object; returns \c false if the QRegularExpression was invalid.
2542
2543 \sa QRegularExpression::match(), QRegularExpression::isValid()
2544*/
2545bool QRegularExpressionMatch::isValid() const
2546{
2547 return d->isValid;
2548}
2549
2550/*!
2551 \internal
2552*/
2553QRegularExpressionMatchIterator::QRegularExpressionMatchIterator(QRegularExpressionMatchIteratorPrivate &dd)
2554 : d(&dd)
2555{
2556}
2557
2558/*!
2559 \since 5.1
2560
2561 Constructs an empty, valid QRegularExpressionMatchIterator object. The
2562 regular expression is set to a default-constructed one; the match type to
2563 QRegularExpression::NoMatch and the match options to
2564 QRegularExpression::NoMatchOption.
2565
2566 Invoking the hasNext() member function on the constructed object will
2567 return false, as the iterator is not iterating on a valid sequence of
2568 matches.
2569*/
2570QRegularExpressionMatchIterator::QRegularExpressionMatchIterator()
2571 : d(new QRegularExpressionMatchIteratorPrivate(QRegularExpression(),
2572 QRegularExpression::NoMatch,
2573 QRegularExpression::NoMatchOption,
2574 QRegularExpressionMatch()))
2575{
2576}
2577
2578/*!
2579 Destroys the QRegularExpressionMatchIterator object.
2580*/
2581QRegularExpressionMatchIterator::~QRegularExpressionMatchIterator()
2582{
2583}
2584
2585QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QRegularExpressionMatchIteratorPrivate)
2586
2587/*!
2588 Constructs a QRegularExpressionMatchIterator object as a copy of \a
2589 iterator.
2590
2591 \sa operator=()
2592*/
2593QRegularExpressionMatchIterator::QRegularExpressionMatchIterator(const QRegularExpressionMatchIterator &iterator)
2594 : d(iterator.d)
2595{
2596}
2597
2598/*!
2599 \fn QRegularExpressionMatchIterator::QRegularExpressionMatchIterator(QRegularExpressionMatchIterator &&iterator)
2600
2601 \since 6.1
2602
2603 Constructs a QRegularExpressionMatchIterator object by moving from \a iterator.
2604
2605 Note that a moved-from QRegularExpressionMatchIterator can only be destroyed
2606 or assigned to. The effect of calling other functions than the destructor
2607 or one of the assignment operators is undefined.
2608
2609 \sa operator=()
2610*/
2611
2612/*!
2613 Assigns the iterator \a iterator to this object, and returns a reference to
2614 the copy.
2615*/
2616QRegularExpressionMatchIterator &QRegularExpressionMatchIterator::operator=(const QRegularExpressionMatchIterator &iterator)
2617{
2618 d = iterator.d;
2619 return *this;
2620}
2621
2622/*!
2623 \fn QRegularExpressionMatchIterator &QRegularExpressionMatchIterator::operator=(QRegularExpressionMatchIterator &&iterator)
2624
2625 Move-assigns the \a iterator to this object, and returns a reference to the
2626 result.
2627
2628 Note that a moved-from QRegularExpressionMatchIterator can only be destroyed
2629 or assigned to. The effect of calling other functions than the destructor
2630 or one of the assignment operators is undefined.
2631*/
2632
2633/*!
2634 \fn void QRegularExpressionMatchIterator::swap(QRegularExpressionMatchIterator &other)
2635 \memberswap{iterator}
2636*/
2637
2638/*!
2639 Returns \c true if the iterator object was obtained as a result from the
2640 QRegularExpression::globalMatch() function invoked on a valid
2641 QRegularExpression object; returns \c false if the QRegularExpression was
2642 invalid.
2643
2644 \sa QRegularExpression::globalMatch(), QRegularExpression::isValid()
2645*/
2646bool QRegularExpressionMatchIterator::isValid() const
2647{
2648 return d->next.isValid();
2649}
2650
2651/*!
2652 Returns \c true if there is at least one match result ahead of the iterator;
2653 otherwise it returns \c false.
2654
2655 \sa next()
2656*/
2657bool QRegularExpressionMatchIterator::hasNext() const
2658{
2659 return d->hasNext();
2660}
2661
2662/*!
2663 Returns the next match result without moving the iterator.
2664
2665 \note Calling this function when the iterator is at the end of the result
2666 set leads to undefined results.
2667*/
2668QRegularExpressionMatch QRegularExpressionMatchIterator::peekNext() const
2669{
2670 if (!hasNext())
2671 qWarning(msg: "QRegularExpressionMatchIterator::peekNext() called on an iterator already at end");
2672
2673 return d->next;
2674}
2675
2676/*!
2677 Returns the next match result and advances the iterator by one position.
2678
2679 \note Calling this function when the iterator is at the end of the result
2680 set leads to undefined results.
2681*/
2682QRegularExpressionMatch QRegularExpressionMatchIterator::next()
2683{
2684 if (!hasNext()) {
2685 qWarning(msg: "QRegularExpressionMatchIterator::next() called on an iterator already at end");
2686 return d.constData()->next;
2687 }
2688
2689 d.detach();
2690 return std::exchange(obj&: d->next, new_val: d->next.d.constData()->nextMatch());
2691}
2692
2693/*!
2694 Returns the QRegularExpression object whose globalMatch() function returned
2695 this object.
2696
2697 \sa QRegularExpression::globalMatch(), matchType(), matchOptions()
2698*/
2699QRegularExpression QRegularExpressionMatchIterator::regularExpression() const
2700{
2701 return d->regularExpression;
2702}
2703
2704/*!
2705 Returns the match type that was used to get this
2706 QRegularExpressionMatchIterator object, that is, the match type that was
2707 passed to QRegularExpression::globalMatch().
2708
2709 \sa QRegularExpression::globalMatch(), regularExpression(), matchOptions()
2710*/
2711QRegularExpression::MatchType QRegularExpressionMatchIterator::matchType() const
2712{
2713 return d->matchType;
2714}
2715
2716/*!
2717 Returns the match options that were used to get this
2718 QRegularExpressionMatchIterator object, that is, the match options that
2719 were passed to QRegularExpression::globalMatch().
2720
2721 \sa QRegularExpression::globalMatch(), regularExpression(), matchType()
2722*/
2723QRegularExpression::MatchOptions QRegularExpressionMatchIterator::matchOptions() const
2724{
2725 return d->matchOptions;
2726}
2727
2728/*!
2729 \internal
2730*/
2731QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
2732{
2733 return QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator(iterator);
2734}
2735
2736/*!
2737 \fn QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel end(const QRegularExpressionMatchIterator &)
2738 \internal
2739*/
2740
2741#ifndef QT_NO_DATASTREAM
2742/*!
2743 \relates QRegularExpression
2744
2745 Writes the regular expression \a re to stream \a out.
2746
2747 \sa {Serializing Qt Data Types}
2748*/
2749QDataStream &operator<<(QDataStream &out, const QRegularExpression &re)
2750{
2751 out << re.pattern() << quint32(re.patternOptions().toInt());
2752 return out;
2753}
2754
2755/*!
2756 \relates QRegularExpression
2757
2758 Reads a regular expression from stream \a in into \a re.
2759
2760 \sa {Serializing Qt Data Types}
2761*/
2762QDataStream &operator>>(QDataStream &in, QRegularExpression &re)
2763{
2764 QString pattern;
2765 quint32 patternOptions;
2766 in >> pattern >> patternOptions;
2767 re.setPattern(pattern);
2768 re.setPatternOptions(QRegularExpression::PatternOptions::fromInt(i: patternOptions));
2769 return in;
2770}
2771#endif
2772
2773#ifndef QT_NO_DEBUG_STREAM
2774/*!
2775 \relates QRegularExpression
2776
2777 Writes the regular expression \a re into the debug object \a debug for
2778 debugging purposes.
2779
2780 \sa {Debugging Techniques}
2781*/
2782QDebug operator<<(QDebug debug, const QRegularExpression &re)
2783{
2784 QDebugStateSaver saver(debug);
2785 debug.nospace() << "QRegularExpression(" << re.pattern() << ", " << re.patternOptions() << ')';
2786 return debug;
2787}
2788
2789/*!
2790 \relates QRegularExpression
2791
2792 Writes the pattern options \a patternOptions into the debug object \a debug
2793 for debugging purposes.
2794
2795 \sa {Debugging Techniques}
2796*/
2797QDebug operator<<(QDebug debug, QRegularExpression::PatternOptions patternOptions)
2798{
2799 QDebugStateSaver saver(debug);
2800 QByteArray flags;
2801
2802 if (patternOptions == QRegularExpression::NoPatternOption) {
2803 flags = "NoPatternOption";
2804 } else {
2805 flags.reserve(asize: 200); // worst case...
2806 if (patternOptions & QRegularExpression::CaseInsensitiveOption)
2807 flags.append(s: "CaseInsensitiveOption|");
2808 if (patternOptions & QRegularExpression::DotMatchesEverythingOption)
2809 flags.append(s: "DotMatchesEverythingOption|");
2810 if (patternOptions & QRegularExpression::MultilineOption)
2811 flags.append(s: "MultilineOption|");
2812 if (patternOptions & QRegularExpression::ExtendedPatternSyntaxOption)
2813 flags.append(s: "ExtendedPatternSyntaxOption|");
2814 if (patternOptions & QRegularExpression::InvertedGreedinessOption)
2815 flags.append(s: "InvertedGreedinessOption|");
2816 if (patternOptions & QRegularExpression::DontCaptureOption)
2817 flags.append(s: "DontCaptureOption|");
2818 if (patternOptions & QRegularExpression::UseUnicodePropertiesOption)
2819 flags.append(s: "UseUnicodePropertiesOption|");
2820 flags.chop(n: 1);
2821 }
2822
2823 debug.nospace() << "QRegularExpression::PatternOptions(" << flags << ')';
2824
2825 return debug;
2826}
2827/*!
2828 \relates QRegularExpressionMatch
2829
2830 Writes the match object \a match into the debug object \a debug for
2831 debugging purposes.
2832
2833 \sa {Debugging Techniques}
2834*/
2835QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match)
2836{
2837 QDebugStateSaver saver(debug);
2838 debug.nospace() << "QRegularExpressionMatch(";
2839
2840 if (!match.isValid()) {
2841 debug << "Invalid)";
2842 return debug;
2843 }
2844
2845 debug << "Valid";
2846
2847 if (match.hasMatch()) {
2848 debug << ", has match: ";
2849 for (int i = 0; i <= match.lastCapturedIndex(); ++i) {
2850 debug << i
2851 << ":(" << match.capturedStart(nth: i) << ", " << match.capturedEnd(nth: i)
2852 << ", " << match.captured(nth: i) << ')';
2853 if (i < match.lastCapturedIndex())
2854 debug << ", ";
2855 }
2856 } else if (match.hasPartialMatch()) {
2857 debug << ", has partial match: ("
2858 << match.capturedStart(nth: 0) << ", "
2859 << match.capturedEnd(nth: 0) << ", "
2860 << match.captured(nth: 0) << ')';
2861 } else {
2862 debug << ", no match";
2863 }
2864
2865 debug << ')';
2866
2867 return debug;
2868}
2869#endif
2870
2871// fool lupdate: make it extract those strings for translation, but don't put them
2872// inside Qt -- they're already inside libpcre (cf. man 3 pcreapi, pcre_compile.c).
2873#if 0
2874
2875/* PCRE is a library of functions to support regular expressions whose syntax
2876and semantics are as close as possible to those of the Perl 5 language.
2877
2878 Written by Philip Hazel
2879 Original API code Copyright (c) 1997-2012 University of Cambridge
2880 New API code Copyright (c) 2015 University of Cambridge
2881
2882-----------------------------------------------------------------------------
2883Redistribution and use in source and binary forms, with or without
2884modification, are permitted provided that the following conditions are met:
2885
2886 * Redistributions of source code must retain the above copyright notice,
2887 this list of conditions and the following disclaimer.
2888
2889 * Redistributions in binary form must reproduce the above copyright
2890 notice, this list of conditions and the following disclaimer in the
2891 documentation and/or other materials provided with the distribution.
2892
2893 * Neither the name of the University of Cambridge nor the names of its
2894 contributors may be used to endorse or promote products derived from
2895 this software without specific prior written permission.
2896
2897THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2898AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2899IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2900ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2901LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2902CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2903SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2904INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2905CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2906ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2907POSSIBILITY OF SUCH DAMAGE.
2908-----------------------------------------------------------------------------
2909*/
2910
2911static const char *pcreCompileErrorCodes[] =
2912{
2913 QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
2914 QT_TRANSLATE_NOOP("QRegularExpression", "\\ at end of pattern"),
2915 QT_TRANSLATE_NOOP("QRegularExpression", "\\c at end of pattern"),
2916 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character follows \\"),
2917 QT_TRANSLATE_NOOP("QRegularExpression", "numbers out of order in {} quantifier"),
2918 QT_TRANSLATE_NOOP("QRegularExpression", "number too big in {} quantifier"),
2919 QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating ] for character class"),
2920 QT_TRANSLATE_NOOP("QRegularExpression", "escape sequence is invalid in character class"),
2921 QT_TRANSLATE_NOOP("QRegularExpression", "range out of order in character class"),
2922 QT_TRANSLATE_NOOP("QRegularExpression", "quantifier does not follow a repeatable item"),
2923 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unexpected repeat"),
2924 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (? or (?-"),
2925 QT_TRANSLATE_NOOP("QRegularExpression", "POSIX named classes are supported only within a class"),
2926 QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
2927 QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis"),
2928 QT_TRANSLATE_NOOP("QRegularExpression", "reference to non-existent subpattern"),
2929 QT_TRANSLATE_NOOP("QRegularExpression", "pattern passed as NULL"),
2930 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognised compile-time option bit(s)"),
2931 QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after (?# comment"),
2932 QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
2933 QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too large"),
2934 QT_TRANSLATE_NOOP("QRegularExpression", "failed to allocate heap memory"),
2935 QT_TRANSLATE_NOOP("QRegularExpression", "unmatched closing parenthesis"),
2936 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: code overflow"),
2937 QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis for condition"),
2938 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is not fixed length"),
2939 QT_TRANSLATE_NOOP("QRegularExpression", "a relative value of zero is not allowed"),
2940 QT_TRANSLATE_NOOP("QRegularExpression", "conditional subpattern contains more than two branches"),
2941 QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?( or (?(?C)"),
2942 QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+ or (?-"),
2943 QT_TRANSLATE_NOOP("QRegularExpression", "unknown POSIX class name"),
2944 QT_TRANSLATE_NOOP("QRegularExpression", "internal error in pcre2_study(): should not occur"),
2945 QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have Unicode support"),
2946 QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"),
2947 QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\x{} or \\o{} is too large"),
2948 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind is too complicated"),
2949 QT_TRANSLATE_NOOP("QRegularExpression", "\\C is not allowed in a lookbehind assertion in UTF-" "16" " mode"),
2950 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2 does not support \\F, \\L, \\l, \\N{name}, \\U, or \\u"),
2951 QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is greater than 255"),
2952 QT_TRANSLATE_NOOP("QRegularExpression", "closing parenthesis for (?C expected"),
2953 QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in (*VERB) name"),
2954 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?P"),
2955 QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in subpattern name (missing terminator?)"),
2956 QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name (PCRE2_DUPNAMES not set)"),
2957 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name must start with a non-digit"),
2958 QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have support for \\P, \\p, or \\X"),
2959 QT_TRANSLATE_NOOP("QRegularExpression", "malformed \\P or \\p sequence"),
2960 QT_TRANSLATE_NOOP("QRegularExpression", "unknown property name after \\P or \\p"),
2961 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum " "32" " code units)"),
2962 QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum " "10000" ")"),
2963 QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"),
2964 QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 in 8-bit non-UTF-8 mode"),
2965 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: overran compiling workspace"),
2966 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: previously-checked referenced subpattern not found"),
2967 QT_TRANSLATE_NOOP("QRegularExpression", "DEFINE subpattern contains more than one branch"),
2968 QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"),
2969 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown newline setting"),
2970 QT_TRANSLATE_NOOP("QRegularExpression", "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number"),
2971 QT_TRANSLATE_NOOP("QRegularExpression", "(?R (recursive pattern call) must be followed by a closing parenthesis"),
2972 QT_TRANSLATE_NOOP("QRegularExpression", "obsolete error (should not occur)"),
2973 QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized or malformed"),
2974 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern number is too big"),
2975 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name expected"),
2976 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: parsed pattern overflow"),
2977 QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"),
2978 QT_TRANSLATE_NOOP("QRegularExpression", "different names for subpatterns of the same number are not allowed"),
2979 QT_TRANSLATE_NOOP("QRegularExpression", "(*MARK) must have an argument"),
2980 QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
2981 QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a printable ASCII character"),
2982 QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a letter or one of [\\]^_?"),
2983 QT_TRANSLATE_NOOP("QRegularExpression", "\\k is not followed by a braced, angle-bracketed, or quoted name"),
2984 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown meta code in check_lookbehinds()"),
2985 QT_TRANSLATE_NOOP("QRegularExpression", "\\N is not supported in a class"),
2986 QT_TRANSLATE_NOOP("QRegularExpression", "callout string is too long"),
2987 QT_TRANSLATE_NOOP("QRegularExpression", "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)"),
2988 QT_TRANSLATE_NOOP("QRegularExpression", "using UTF is disabled by the application"),
2989 QT_TRANSLATE_NOOP("QRegularExpression", "using UCP is disabled by the application"),
2990 QT_TRANSLATE_NOOP("QRegularExpression", "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)"),
2991 QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\u.... sequence is too large"),
2992 QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{} or \\N{U+}"),
2993 QT_TRANSLATE_NOOP("QRegularExpression", "syntax error or number too big in (?(VERSION condition"),
2994 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in auto_possessify()"),
2995 QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating delimiter for callout with string argument"),
2996 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized string delimiter follows (?C"),
2997 QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled by the application"),
2998 QT_TRANSLATE_NOOP("QRegularExpression", "(?| and/or (?J: or (?x: parentheses are too deeply nested"),
2999 QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled in this PCRE2 library"),
3000 QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too complicated"),
3001 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is too long"),
3002 QT_TRANSLATE_NOOP("QRegularExpression", "pattern string is longer than the limit set by the application"),
3003 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown code in parsed pattern"),
3004 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: bad code value in parsed_skip()"),
3005 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode"),
3006 QT_TRANSLATE_NOOP("QRegularExpression", "invalid option bits with PCRE2_LITERAL"),
3007 QT_TRANSLATE_NOOP("QRegularExpression", "\\N{U+dddd} is supported only in Unicode (UTF) mode"),
3008 QT_TRANSLATE_NOOP("QRegularExpression", "invalid hyphen in option setting"),
3009 QT_TRANSLATE_NOOP("QRegularExpression", "(*alpha_assertion) not recognized"),
3010 QT_TRANSLATE_NOOP("QRegularExpression", "script runs require Unicode support, which this version of PCRE2 does not have"),
3011 QT_TRANSLATE_NOOP("QRegularExpression", "too many capturing groups (maximum 65535)"),
3012 QT_TRANSLATE_NOOP("QRegularExpression", "atomic assertion expected after (?( or (?(?C)"),
3013 QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
3014 QT_TRANSLATE_NOOP("QRegularExpression", "no match"),
3015 QT_TRANSLATE_NOOP("QRegularExpression", "partial match"),
3016 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 1 byte missing at end"),
3017 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 2 bytes missing at end"),
3018 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 3 bytes missing at end"),
3019 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 4 bytes missing at end"),
3020 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5 bytes missing at end"),
3021 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 2 top bits not 0x80"),
3022 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 3 top bits not 0x80"),
3023 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 4 top bits not 0x80"),
3024 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 5 top bits not 0x80"),
3025 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 6 top bits not 0x80"),
3026 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5-byte character is not allowed (RFC 3629)"),
3027 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 6-byte character is not allowed (RFC 3629)"),
3028 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points greater than 0x10ffff are not defined"),
3029 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points 0xd800-0xdfff are not defined"),
3030 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 2-byte sequence"),
3031 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 3-byte sequence"),
3032 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 4-byte sequence"),
3033 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 5-byte sequence"),
3034 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 6-byte sequence"),
3035 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: isolated byte with 0x80 bit set"),
3036 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: illegal byte (0xfe or 0xff)"),
3037 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: missing low surrogate at end"),
3038 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: invalid low surrogate"),
3039 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: isolated low surrogate"),
3040 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points 0xd800-0xdfff are not defined"),
3041 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points greater than 0x10ffff are not defined"),
3042 QT_TRANSLATE_NOOP("QRegularExpression", "bad data value"),
3043 QT_TRANSLATE_NOOP("QRegularExpression", "patterns do not all use the same character tables"),
3044 QT_TRANSLATE_NOOP("QRegularExpression", "magic number missing"),
3045 QT_TRANSLATE_NOOP("QRegularExpression", "pattern compiled in wrong mode: 8/16/32-bit error"),
3046 QT_TRANSLATE_NOOP("QRegularExpression", "bad offset value"),
3047 QT_TRANSLATE_NOOP("QRegularExpression", "bad option value"),
3048 QT_TRANSLATE_NOOP("QRegularExpression", "invalid replacement string"),
3049 QT_TRANSLATE_NOOP("QRegularExpression", "bad offset into UTF string"),
3050 QT_TRANSLATE_NOOP("QRegularExpression", "callout error code"),
3051 QT_TRANSLATE_NOOP("QRegularExpression", "invalid data in workspace for DFA restart"),
3052 QT_TRANSLATE_NOOP("QRegularExpression", "too much recursion for DFA matching"),
3053 QT_TRANSLATE_NOOP("QRegularExpression", "backreference condition or recursion test is not supported for DFA matching"),
3054 QT_TRANSLATE_NOOP("QRegularExpression", "function is not supported for DFA matching"),
3055 QT_TRANSLATE_NOOP("QRegularExpression", "pattern contains an item that is not supported for DFA matching"),
3056 QT_TRANSLATE_NOOP("QRegularExpression", "workspace size exceeded in DFA matching"),
3057 QT_TRANSLATE_NOOP("QRegularExpression", "internal error - pattern overwritten?"),
3058 QT_TRANSLATE_NOOP("QRegularExpression", "bad JIT option"),
3059 QT_TRANSLATE_NOOP("QRegularExpression", "JIT stack limit reached"),
3060 QT_TRANSLATE_NOOP("QRegularExpression", "match limit exceeded"),
3061 QT_TRANSLATE_NOOP("QRegularExpression", "no more memory"),
3062 QT_TRANSLATE_NOOP("QRegularExpression", "unknown substring"),
3063 QT_TRANSLATE_NOOP("QRegularExpression", "non-unique substring name"),
3064 QT_TRANSLATE_NOOP("QRegularExpression", "NULL argument passed"),
3065 QT_TRANSLATE_NOOP("QRegularExpression", "nested recursion at the same subject position"),
3066 QT_TRANSLATE_NOOP("QRegularExpression", "matching depth limit exceeded"),
3067 QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not available"),
3068 QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not set"),
3069 QT_TRANSLATE_NOOP("QRegularExpression", "offset limit set without PCRE2_USE_OFFSET_LIMIT"),
3070 QT_TRANSLATE_NOOP("QRegularExpression", "bad escape sequence in replacement string"),
3071 QT_TRANSLATE_NOOP("QRegularExpression", "expected closing curly bracket in replacement string"),
3072 QT_TRANSLATE_NOOP("QRegularExpression", "bad substitution in replacement string"),
3073 QT_TRANSLATE_NOOP("QRegularExpression", "match with end before start or start moved backwards is not supported"),
3074 QT_TRANSLATE_NOOP("QRegularExpression", "too many replacements (more than INT_MAX)"),
3075 QT_TRANSLATE_NOOP("QRegularExpression", "bad serialized data"),
3076 QT_TRANSLATE_NOOP("QRegularExpression", "heap limit exceeded"),
3077 QT_TRANSLATE_NOOP("QRegularExpression", "invalid syntax"),
3078 QT_TRANSLATE_NOOP("QRegularExpression", "internal error - duplicate substitution match"),
3079 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching"),
3080 QT_TRANSLATE_NOOP("QRegularExpression", "INTERNAL ERROR: invalid substring offset")
3081};
3082#endif // #if 0
3083
3084QT_END_NAMESPACE
3085

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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