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#ifndef QREGULAREXPRESSION_H
7#define QREGULAREXPRESSION_H
8
9#include <QtCore/qglobal.h>
10#include <QtCore/qstring.h>
11#include <QtCore/qstringview.h>
12#include <QtCore/qshareddata.h>
13#include <QtCore/qvariant.h>
14
15#include <iterator>
16
17QT_REQUIRE_CONFIG(regularexpression);
18
19QT_BEGIN_NAMESPACE
20
21class QRegularExpressionMatch;
22class QRegularExpressionMatchIterator;
23struct QRegularExpressionPrivate;
24class QRegularExpression;
25
26QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QRegularExpressionPrivate, Q_CORE_EXPORT)
27
28Q_CORE_EXPORT size_t qHash(const QRegularExpression &key, size_t seed = 0) noexcept;
29
30class Q_CORE_EXPORT QRegularExpression
31{
32public:
33 enum PatternOption {
34 NoPatternOption = 0x0000,
35 CaseInsensitiveOption = 0x0001,
36 DotMatchesEverythingOption = 0x0002,
37 MultilineOption = 0x0004,
38 ExtendedPatternSyntaxOption = 0x0008,
39 InvertedGreedinessOption = 0x0010,
40 DontCaptureOption = 0x0020,
41 UseUnicodePropertiesOption = 0x0040,
42 // Formerly (no-ops deprecated in 5.12, removed 6.0):
43 // OptimizeOnFirstUsageOption = 0x0080,
44 // DontAutomaticallyOptimizeOption = 0x0100,
45 };
46 Q_DECLARE_FLAGS(PatternOptions, PatternOption)
47
48 PatternOptions patternOptions() const;
49 void setPatternOptions(PatternOptions options);
50
51 QRegularExpression();
52 explicit QRegularExpression(const QString &pattern, PatternOptions options = NoPatternOption);
53 QRegularExpression(const QRegularExpression &re) noexcept;
54 QRegularExpression(QRegularExpression &&re) = default;
55 ~QRegularExpression();
56 QRegularExpression &operator=(const QRegularExpression &re) noexcept;
57 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QRegularExpression)
58
59 void swap(QRegularExpression &other) noexcept { d.swap(other&: other.d); }
60
61 QString pattern() const;
62 void setPattern(const QString &pattern);
63
64 [[nodiscard]]
65 bool isValid() const;
66 qsizetype patternErrorOffset() const;
67 QString errorString() const;
68
69 int captureCount() const;
70 QStringList namedCaptureGroups() const;
71
72 enum MatchType {
73 NormalMatch = 0,
74 PartialPreferCompleteMatch,
75 PartialPreferFirstMatch,
76 NoMatch
77 };
78
79 enum MatchOption {
80 NoMatchOption = 0x0000,
81 AnchorAtOffsetMatchOption = 0x0001,
82 AnchoredMatchOption Q_DECL_ENUMERATOR_DEPRECATED_X(
83 "Use AnchorAtOffsetMatchOption instead") = AnchorAtOffsetMatchOption, // Rename@Qt6.0
84 DontCheckSubjectStringMatchOption = 0x0002
85 };
86 Q_DECLARE_FLAGS(MatchOptions, MatchOption)
87
88 [[nodiscard]]
89 QRegularExpressionMatch match(const QString &subject,
90 qsizetype offset = 0,
91 MatchType matchType = NormalMatch,
92 MatchOptions matchOptions = NoMatchOption) const;
93
94#if QT_DEPRECATED_SINCE(6, 8)
95 [[nodiscard]]
96 QT_DEPRECATED_VERSION_X_6_8("Use matchView instead.")
97 QRegularExpressionMatch match(QStringView subjectView,
98 qsizetype offset = 0,
99 MatchType matchType = NormalMatch,
100 MatchOptions matchOptions = NoMatchOption) const;
101#endif
102
103 [[nodiscard]]
104 QRegularExpressionMatch matchView(QStringView subjectView,
105 qsizetype offset = 0,
106 MatchType matchType = NormalMatch,
107 MatchOptions matchOptions = NoMatchOption) const;
108
109 [[nodiscard]]
110 QRegularExpressionMatchIterator globalMatch(const QString &subject,
111 qsizetype offset = 0,
112 MatchType matchType = NormalMatch,
113 MatchOptions matchOptions = NoMatchOption) const;
114
115#if QT_DEPRECATED_SINCE(6, 8)
116 [[nodiscard]]
117 QT_DEPRECATED_VERSION_X_6_8("Use globalMatchView instead.")
118 QRegularExpressionMatchIterator globalMatch(QStringView subjectView,
119 qsizetype offset = 0,
120 MatchType matchType = NormalMatch,
121 MatchOptions matchOptions = NoMatchOption) const;
122#endif
123
124 [[nodiscard]]
125 QRegularExpressionMatchIterator globalMatchView(QStringView subjectView,
126 qsizetype offset = 0,
127 MatchType matchType = NormalMatch,
128 MatchOptions matchOptions = NoMatchOption) const;
129
130 void optimize() const;
131
132 enum WildcardConversionOption {
133 DefaultWildcardConversion = 0x0,
134 UnanchoredWildcardConversion = 0x1,
135 NonPathWildcardConversion = 0x2,
136 };
137 Q_DECLARE_FLAGS(WildcardConversionOptions, WildcardConversionOption)
138
139 static QString escape(const QString &str)
140 {
141 return escape(str: qToStringViewIgnoringNull(s: str));
142 }
143
144 static QString wildcardToRegularExpression(const QString &str, WildcardConversionOptions options = DefaultWildcardConversion)
145 {
146 return wildcardToRegularExpression(str: qToStringViewIgnoringNull(s: str), options);
147 }
148
149 static inline QString anchoredPattern(const QString &expression)
150 {
151 return anchoredPattern(expression: qToStringViewIgnoringNull(s: expression));
152 }
153
154 static QString escape(QStringView str);
155 static QString wildcardToRegularExpression(QStringView str, WildcardConversionOptions options = DefaultWildcardConversion);
156 static QString anchoredPattern(QStringView expression);
157
158 static QRegularExpression fromWildcard(QStringView pattern, Qt::CaseSensitivity cs = Qt::CaseInsensitive,
159 WildcardConversionOptions options = DefaultWildcardConversion);
160
161 bool operator==(const QRegularExpression &re) const;
162 inline bool operator!=(const QRegularExpression &re) const { return !operator==(re); }
163
164private:
165 friend struct QRegularExpressionPrivate;
166 friend class QRegularExpressionMatch;
167 friend struct QRegularExpressionMatchPrivate;
168 friend class QRegularExpressionMatchIterator;
169 friend Q_CORE_EXPORT size_t qHash(const QRegularExpression &key, size_t seed) noexcept;
170
171 QRegularExpression(QRegularExpressionPrivate &dd);
172 QExplicitlySharedDataPointer<QRegularExpressionPrivate> d;
173};
174
175Q_DECLARE_SHARED(QRegularExpression)
176Q_DECLARE_OPERATORS_FOR_FLAGS(QRegularExpression::PatternOptions)
177Q_DECLARE_OPERATORS_FOR_FLAGS(QRegularExpression::MatchOptions)
178
179#ifndef QT_NO_DATASTREAM
180Q_CORE_EXPORT QDataStream &operator<<(QDataStream &out, const QRegularExpression &re);
181Q_CORE_EXPORT QDataStream &operator>>(QDataStream &in, QRegularExpression &re);
182#endif
183
184#ifndef QT_NO_DEBUG_STREAM
185Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QRegularExpression &re);
186Q_CORE_EXPORT QDebug operator<<(QDebug debug, QRegularExpression::PatternOptions patternOptions);
187#endif
188
189struct QRegularExpressionMatchPrivate;
190QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QRegularExpressionMatchPrivate, Q_CORE_EXPORT)
191
192class Q_CORE_EXPORT QRegularExpressionMatch
193{
194public:
195 QRegularExpressionMatch();
196 ~QRegularExpressionMatch();
197 QRegularExpressionMatch(const QRegularExpressionMatch &match);
198 QRegularExpressionMatch(QRegularExpressionMatch &&match) = default;
199 QRegularExpressionMatch &operator=(const QRegularExpressionMatch &match);
200 QRegularExpressionMatch &operator=(QRegularExpressionMatch &&match) noexcept
201 { d.swap(other&: match.d); return *this; }
202 void swap(QRegularExpressionMatch &other) noexcept { d.swap(other&: other.d); }
203
204 QRegularExpression regularExpression() const;
205 QRegularExpression::MatchType matchType() const;
206 QRegularExpression::MatchOptions matchOptions() const;
207
208 bool hasMatch() const;
209 bool hasPartialMatch() const;
210
211 bool isValid() const;
212
213 int lastCapturedIndex() const;
214
215 bool hasCaptured(const QString &name) const
216 { return hasCaptured(name: QStringView(name)); }
217 bool hasCaptured(QStringView name) const;
218 bool hasCaptured(int nth) const;
219
220 QString captured(int nth = 0) const;
221 QStringView capturedView(int nth = 0) const;
222
223 QString captured(const QString &name) const
224 { return captured(name: QStringView(name)); }
225 QString captured(QStringView name) const;
226 QStringView capturedView(QStringView name) const;
227
228 QStringList capturedTexts() const;
229
230 qsizetype capturedStart(int nth = 0) const;
231 qsizetype capturedLength(int nth = 0) const;
232 qsizetype capturedEnd(int nth = 0) const;
233
234 qsizetype capturedStart(const QString &name) const
235 { return capturedStart(name: QStringView(name)); }
236 qsizetype capturedLength(const QString &name) const
237 { return capturedLength(name: QStringView(name)); }
238 qsizetype capturedEnd(const QString &name) const
239 { return capturedEnd(name: QStringView(name)); }
240
241 qsizetype capturedStart(QStringView name) const;
242 qsizetype capturedLength(QStringView name) const;
243 qsizetype capturedEnd(QStringView name) const;
244
245private:
246 friend class QRegularExpression;
247 friend struct QRegularExpressionMatchPrivate;
248 friend class QRegularExpressionMatchIterator;
249
250 QRegularExpressionMatch(QRegularExpressionMatchPrivate &dd);
251 QExplicitlySharedDataPointer<QRegularExpressionMatchPrivate> d;
252};
253
254Q_DECLARE_SHARED(QRegularExpressionMatch)
255
256#ifndef QT_NO_DEBUG_STREAM
257Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match);
258#endif
259
260namespace QtPrivate {
261class QRegularExpressionMatchIteratorRangeBasedForIterator;
262class QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel {};
263}
264
265struct QRegularExpressionMatchIteratorPrivate;
266QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QRegularExpressionMatchIteratorPrivate, Q_CORE_EXPORT)
267
268class Q_CORE_EXPORT QRegularExpressionMatchIterator
269{
270public:
271 QRegularExpressionMatchIterator();
272 ~QRegularExpressionMatchIterator();
273 QRegularExpressionMatchIterator(const QRegularExpressionMatchIterator &iterator);
274 QRegularExpressionMatchIterator(QRegularExpressionMatchIterator &&iterator) = default;
275 QRegularExpressionMatchIterator &operator=(const QRegularExpressionMatchIterator &iterator);
276 QRegularExpressionMatchIterator &operator=(QRegularExpressionMatchIterator &&iterator) noexcept
277 { d.swap(other&: iterator.d); return *this; }
278 void swap(QRegularExpressionMatchIterator &other) noexcept { d.swap(other&: other.d); }
279
280 bool isValid() const;
281
282 bool hasNext() const;
283 QRegularExpressionMatch next();
284 QRegularExpressionMatch peekNext() const;
285
286 QRegularExpression regularExpression() const;
287 QRegularExpression::MatchType matchType() const;
288 QRegularExpression::MatchOptions matchOptions() const;
289
290private:
291 friend class QRegularExpression;
292 friend Q_CORE_EXPORT QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator);
293 friend QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel end(const QRegularExpressionMatchIterator &) { return {}; }
294
295 QRegularExpressionMatchIterator(QRegularExpressionMatchIteratorPrivate &dd);
296 QExplicitlySharedDataPointer<QRegularExpressionMatchIteratorPrivate> d;
297};
298
299namespace QtPrivate {
300
301// support for range-based for loop
302class QRegularExpressionMatchIteratorRangeBasedForIterator
303{
304public:
305 using value_type = QRegularExpressionMatch;
306 using difference_type = int;
307 using reference_type = const QRegularExpressionMatch &;
308 using pointer_type = const QRegularExpressionMatch *;
309 using iterator_category = std::forward_iterator_tag;
310
311 QRegularExpressionMatchIteratorRangeBasedForIterator()
312 : m_atEnd(true)
313 {
314 }
315
316 explicit QRegularExpressionMatchIteratorRangeBasedForIterator(const QRegularExpressionMatchIterator &iterator)
317 : m_matchIterator(iterator),
318 m_currentMatch(),
319 m_atEnd(false)
320 {
321 ++*this;
322 }
323
324 const QRegularExpressionMatch &operator*() const
325 {
326 Q_ASSERT_X(!m_atEnd, Q_FUNC_INFO, "operator* called on an iterator already at the end");
327 return m_currentMatch;
328 }
329
330 QRegularExpressionMatchIteratorRangeBasedForIterator &operator++()
331 {
332 Q_ASSERT_X(!m_atEnd, Q_FUNC_INFO, "operator++ called on an iterator already at the end");
333 if (m_matchIterator.hasNext()) {
334 m_currentMatch = m_matchIterator.next();
335 } else {
336 m_currentMatch = QRegularExpressionMatch();
337 m_atEnd = true;
338 }
339
340 return *this;
341 }
342
343 QRegularExpressionMatchIteratorRangeBasedForIterator operator++(int)
344 {
345 QRegularExpressionMatchIteratorRangeBasedForIterator i = *this;
346 ++*this;
347 return i;
348 }
349
350private:
351 // [input.iterators] imposes operator== on us. Unfortunately, it's not
352 // trivial to implement, so just do the bare minimum to satifisfy
353 // Cpp17EqualityComparable.
354 friend bool operator==(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs,
355 const QRegularExpressionMatchIteratorRangeBasedForIterator &rhs) noexcept
356 {
357 return (&lhs == &rhs);
358 }
359
360 friend bool operator!=(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs,
361 const QRegularExpressionMatchIteratorRangeBasedForIterator &rhs) noexcept
362 {
363 return !(lhs == rhs);
364 }
365
366 // This is what we really use in a range-based for.
367 friend bool operator==(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs,
368 QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel) noexcept
369 {
370 return lhs.m_atEnd;
371 }
372
373 friend bool operator!=(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs,
374 QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel) noexcept
375 {
376 return !lhs.m_atEnd;
377 }
378
379 QRegularExpressionMatchIterator m_matchIterator;
380 QRegularExpressionMatch m_currentMatch;
381 bool m_atEnd;
382};
383
384} // namespace QtPrivate
385
386Q_DECLARE_SHARED(QRegularExpressionMatchIterator)
387
388QT_END_NAMESPACE
389
390#endif // QREGULAREXPRESSION_H
391

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