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