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 | |
52 | QT_REQUIRE_CONFIG(regularexpression); |
53 | |
54 | QT_BEGIN_NAMESPACE |
55 | |
56 | class QLatin1String; |
57 | |
58 | class QRegularExpressionMatch; |
59 | class QRegularExpressionMatchIterator; |
60 | struct QRegularExpressionPrivate; |
61 | class QRegularExpression; |
62 | |
63 | Q_CORE_EXPORT size_t qHash(const QRegularExpression &key, size_t seed = 0) noexcept; |
64 | |
65 | class Q_CORE_EXPORT QRegularExpression |
66 | { |
67 | public: |
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 | |
176 | private: |
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 | |
187 | Q_DECLARE_SHARED(QRegularExpression) |
188 | Q_DECLARE_OPERATORS_FOR_FLAGS(QRegularExpression::PatternOptions) |
189 | Q_DECLARE_OPERATORS_FOR_FLAGS(QRegularExpression::MatchOptions) |
190 | |
191 | #ifndef QT_NO_DATASTREAM |
192 | Q_CORE_EXPORT QDataStream &operator<<(QDataStream &out, const QRegularExpression &re); |
193 | Q_CORE_EXPORT QDataStream &operator>>(QDataStream &in, QRegularExpression &re); |
194 | #endif |
195 | |
196 | #ifndef QT_NO_DEBUG_STREAM |
197 | Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QRegularExpression &re); |
198 | Q_CORE_EXPORT QDebug operator<<(QDebug debug, QRegularExpression::PatternOptions patternOptions); |
199 | #endif |
200 | |
201 | struct QRegularExpressionMatchPrivate; |
202 | |
203 | class Q_CORE_EXPORT QRegularExpressionMatch |
204 | { |
205 | public: |
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 | |
255 | private: |
256 | friend class QRegularExpression; |
257 | friend struct QRegularExpressionMatchPrivate; |
258 | friend class QRegularExpressionMatchIterator; |
259 | |
260 | QRegularExpressionMatch(QRegularExpressionMatchPrivate &dd); |
261 | QExplicitlySharedDataPointer<QRegularExpressionMatchPrivate> d; |
262 | }; |
263 | |
264 | Q_DECLARE_SHARED(QRegularExpressionMatch) |
265 | |
266 | #ifndef QT_NO_DEBUG_STREAM |
267 | Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match); |
268 | #endif |
269 | |
270 | namespace QtPrivate { |
271 | class QRegularExpressionMatchIteratorRangeBasedForIterator; |
272 | class QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel {}; |
273 | } |
274 | |
275 | struct QRegularExpressionMatchIteratorPrivate; |
276 | |
277 | class Q_CORE_EXPORT QRegularExpressionMatchIterator |
278 | { |
279 | public: |
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 | |
298 | private: |
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 | |
307 | namespace QtPrivate { |
308 | |
309 | // support for range-based for loop |
310 | class QRegularExpressionMatchIteratorRangeBasedForIterator |
311 | { |
312 | public: |
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 | |
358 | private: |
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 | |
394 | Q_DECLARE_SHARED(QRegularExpressionMatchIterator) |
395 | |
396 | QT_END_NAMESPACE |
397 | |
398 | #endif // QREGULAREXPRESSION_H |
399 | |