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