Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qregularexpression.cpp
Go to the documentation of this file.
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
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
27
28using namespace Qt::StringLiterals;
29
666static int convertToPcreOptions(QRegularExpression::PatternOptions patternOptions)
667{
668 int options = 0;
669
671 options |= PCRE2_CASELESS;
673 options |= PCRE2_DOTALL;
674 if (patternOptions & QRegularExpression::MultilineOption)
675 options |= PCRE2_MULTILINE;
677 options |= PCRE2_EXTENDED;
679 options |= PCRE2_UNGREEDY;
680 if (patternOptions & QRegularExpression::DontCaptureOption)
681 options |= PCRE2_NO_AUTO_CAPTURE;
683 options |= PCRE2_UCP;
684
685 return options;
686}
687
691static int convertToPcreOptions(QRegularExpression::MatchOptions matchOptions)
692{
693 int options = 0;
694
696 options |= PCRE2_ANCHORED;
698 options |= PCRE2_NO_UTF_CHECK;
699
700 return options;
701}
702
704{
708
710 void compilePattern();
711 void getPatternInfo();
712 void optimizePattern();
713
717 };
718
721 CheckSubjectStringOption checkSubjectStringOption = CheckSubjectString,
722 const QRegularExpressionMatchPrivate *previous = nullptr) const;
723
725
726 // sizeof(QSharedData) == 4, so start our members with an enum
727 QRegularExpression::PatternOptions patternOptions;
729
730 // *All* of the following members are managed while holding this mutex,
731 // except for isDirty which is set to true by QRegularExpression setters
732 // (right after a detach happened).
733 mutable QMutex mutex;
734
735 // The PCRE code pointer is reference-counted by the QRegularExpressionPrivate
736 // objects themselves; when the private is copied (i.e. a detach happened)
737 // it is set to nullptr
738 pcre2_code_16 *compiledPattern;
744};
745
747{
749 const QString &subjectStorage,
752 QRegularExpression::MatchOptions matchOptions);
753
755
757
758 // subject is what we match upon. If we've been asked to match over
759 // a QString, then subjectStorage is a copy of that string
760 // (so that it's kept alive by us)
763
765 const QRegularExpression::MatchOptions matchOptions;
766
767 // the capturedOffsets vector contains pairs of (start, end) positions
768 // for each captured substring
770
772
773 bool hasMatch = false;
774 bool hasPartialMatch = false;
775 bool isValid = false;
776};
777
779{
782 QRegularExpression::MatchOptions matchOptions,
784
785 bool hasNext() const;
789 const QRegularExpression::MatchOptions matchOptions;
790};
791
801{
802 if (pattern.isValidUtf16()) {
803 qWarning("%s(): called on an invalid QRegularExpression object "
804 "(pattern is '%ls')", where, qUtf16Printable(pattern));
805 } else {
806 qWarning("%s(): called on an invalid QRegularExpression object", where);
807 }
808}
809
814 : d(&dd)
815{
816}
817
822 : QSharedData(),
823 patternOptions(),
824 pattern(),
825 mutex(),
826 compiledPattern(nullptr),
827 errorCode(0),
828 errorOffset(-1),
829 capturingCount(0),
830 usingCrLfNewlines(false),
831 isDirty(true)
832{
833}
834
839{
841}
842
854 patternOptions(other.patternOptions),
856 mutex(),
857 compiledPattern(nullptr),
858 errorCode(0),
859 errorOffset(-1),
860 capturingCount(0),
861 usingCrLfNewlines(false),
862 isDirty(true)
863{
864}
865
870{
871 pcre2_code_free_16(compiledPattern);
872 compiledPattern = nullptr;
873 errorCode = 0;
874 errorOffset = -1;
875 capturingCount = 0;
876 usingCrLfNewlines = false;
877}
878
883{
884 const QMutexLocker lock(&mutex);
885
886 if (!isDirty)
887 return;
888
889 isDirty = false;
891
893 options |= PCRE2_UTF;
894
895 PCRE2_SIZE patternErrorOffset;
896 compiledPattern = pcre2_compile_16(reinterpret_cast<PCRE2_SPTR16>(pattern.constData()),
897 pattern.size(),
898 options,
899 &errorCode,
900 &patternErrorOffset,
901 nullptr);
902
903 if (!compiledPattern) {
904 errorOffset = qsizetype(patternErrorOffset);
905 return;
906 } else {
907 // ignore whatever PCRE2 wrote into errorCode -- leave it to 0 to mean "no error"
908 errorCode = 0;
909 }
910
913}
914
919{
921
922 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_CAPTURECOUNT, &capturingCount);
923
924 // detect the settings for the newline
925 unsigned int patternNewlineSetting;
926 if (pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NEWLINE, &patternNewlineSetting) != 0) {
927 // no option was specified in the regexp, grab PCRE build defaults
928 pcre2_config_16(PCRE2_CONFIG_NEWLINE, &patternNewlineSetting);
929 }
930
931 usingCrLfNewlines = (patternNewlineSetting == PCRE2_NEWLINE_CRLF) ||
932 (patternNewlineSetting == PCRE2_NEWLINE_ANY) ||
933 (patternNewlineSetting == PCRE2_NEWLINE_ANYCRLF);
934
935 unsigned int hasJOptionChanged;
936 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_JCHANGED, &hasJOptionChanged);
937 if (Q_UNLIKELY(hasJOptionChanged)) {
938 qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%ls'\n is using the (?J) option; duplicate capturing group names are not supported by Qt",
940 }
941}
942
943
944/*
945 Simple "smartpointer" wrapper around a pcre2_jit_stack_16, to be used with
946 QThreadStorage.
947*/
948namespace {
949struct PcreJitStackFree
950{
951 void operator()(pcre2_jit_stack_16 *stack)
952 {
953 if (stack)
954 pcre2_jit_stack_free_16(stack);
955 }
956};
957Q_CONSTINIT static thread_local std::unique_ptr<pcre2_jit_stack_16, PcreJitStackFree> jitStacks;
958}
959
963static pcre2_jit_stack_16 *qtPcreCallback(void *)
964{
965 return jitStacks.get();
966}
967
971static bool isJitEnabled()
972{
973 QByteArray jitEnvironment = qgetenv("QT_ENABLE_REGEXP_JIT");
974 if (!jitEnvironment.isEmpty()) {
975 bool ok;
976 int enableJit = jitEnvironment.toInt(&ok);
977 return ok ? (enableJit != 0) : true;
978 }
979
980#ifdef QT_DEBUG
981 return false;
982#elif defined(Q_OS_MACOS)
983 return !qt_mac_runningUnderRosetta();
984#else
985 return true;
986#endif
987}
988
999{
1001
1002 static const bool enableJit = isJitEnabled();
1003
1004 if (!enableJit)
1005 return;
1006
1007 pcre2_jit_compile_16(compiledPattern, PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_PARTIAL_HARD);
1008}
1009
1017{
1018 Q_ASSERT(!name.isEmpty());
1019
1020 if (!compiledPattern)
1021 return -1;
1022
1023 // See the other usages of pcre2_pattern_info_16 for more details about this
1024 PCRE2_SPTR16 *namedCapturingTable;
1025 unsigned int namedCapturingTableEntryCount;
1026 unsigned int namedCapturingTableEntrySize;
1027
1028 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
1029 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
1030 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
1031
1032 for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
1033 const auto currentNamedCapturingTableRow =
1034 reinterpret_cast<const char16_t *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
1035
1036 if (name == (currentNamedCapturingTableRow + 1)) {
1037 const int index = *currentNamedCapturingTableRow;
1038 return index;
1039 }
1040 }
1041
1042 return -1;
1043}
1044
1052static int safe_pcre2_match_16(const pcre2_code_16 *code,
1053 PCRE2_SPTR16 subject, qsizetype length,
1054 qsizetype startOffset, int options,
1055 pcre2_match_data_16 *matchData,
1056 pcre2_match_context_16 *matchContext)
1057{
1058 int result = pcre2_match_16(code, subject, length,
1059 startOffset, options, matchData, matchContext);
1060
1061 if (result == PCRE2_ERROR_JIT_STACKLIMIT && !jitStacks) {
1062 // The default JIT stack size in PCRE is 32K,
1063 // we allocate from 32K up to 512K.
1064 jitStacks.reset(pcre2_jit_stack_create_16(32 * 1024, 512 * 1024, NULL));
1065
1066 result = pcre2_match_16(code, subject, length,
1067 startOffset, options, matchData, matchContext);
1068 }
1069
1070 return result;
1071}
1072
1103 CheckSubjectStringOption checkSubjectStringOption,
1104 const QRegularExpressionMatchPrivate *previous) const
1105{
1106 Q_ASSERT(priv);
1107 Q_ASSUME(priv != previous);
1108
1109 const qsizetype subjectLength = priv->subject.size();
1110
1111 if (offset < 0)
1112 offset += subjectLength;
1113
1114 if (offset < 0 || offset > subjectLength)
1115 return;
1116
1118 qtWarnAboutInvalidRegularExpression(pattern, "QRegularExpressionPrivate::doMatch");
1119 return;
1120 }
1121
1122 // skip doing the actual matching if NoMatch type was requested
1123 if (priv->matchType == QRegularExpression::NoMatch) {
1124 priv->isValid = true;
1125 return;
1126 }
1127
1128 int pcreOptions = convertToPcreOptions(priv->matchOptions);
1129
1131 pcreOptions |= PCRE2_PARTIAL_SOFT;
1133 pcreOptions |= PCRE2_PARTIAL_HARD;
1134
1135 if (checkSubjectStringOption == DontCheckSubjectString)
1136 pcreOptions |= PCRE2_NO_UTF_CHECK;
1137
1138 bool previousMatchWasEmpty = false;
1139 if (previous && previous->hasMatch &&
1140 (previous->capturedOffsets.at(0) == previous->capturedOffsets.at(1))) {
1141 previousMatchWasEmpty = true;
1142 }
1143
1144 pcre2_match_context_16 *matchContext = pcre2_match_context_create_16(nullptr);
1145 pcre2_jit_stack_assign_16(matchContext, &qtPcreCallback, nullptr);
1146 pcre2_match_data_16 *matchData = pcre2_match_data_create_from_pattern_16(compiledPattern, nullptr);
1147
1148 // PCRE does not accept a null pointer as subject string, even if
1149 // its length is zero. We however allow it in input: a QStringView
1150 // subject may have data == nullptr. In this case, to keep PCRE
1151 // happy, pass a pointer to a dummy character.
1152 const char16_t dummySubject = 0;
1153 const char16_t * const subjectUtf16 = [&]()
1154 {
1155 const auto subjectUtf16 = priv->subject.utf16();
1156 if (subjectUtf16)
1157 return subjectUtf16;
1158 Q_ASSERT(subjectLength == 0);
1159 return &dummySubject;
1160 }();
1161
1162 int result;
1163
1164 if (!previousMatchWasEmpty) {
1166 reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), subjectLength,
1167 offset, pcreOptions,
1168 matchData, matchContext);
1169 } else {
1171 reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), subjectLength,
1172 offset, pcreOptions | PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED,
1173 matchData, matchContext);
1174
1175 if (result == PCRE2_ERROR_NOMATCH) {
1176 ++offset;
1177
1179 && offset < subjectLength
1180 && subjectUtf16[offset - 1] == u'\r'
1181 && subjectUtf16[offset] == u'\n') {
1182 ++offset;
1183 } else if (offset < subjectLength
1184 && QChar::isLowSurrogate(subjectUtf16[offset])) {
1185 ++offset;
1186 }
1187
1189 reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), subjectLength,
1190 offset, pcreOptions,
1191 matchData, matchContext);
1192 }
1193 }
1194
1195#ifdef QREGULAREXPRESSION_DEBUG
1196 qDebug() << "Matching" << pattern << "against" << subject
1197 << "offset" << offset
1198 << priv->matchType << priv->matchOptions << previousMatchWasEmpty
1199 << "result" << result;
1200#endif
1201
1202 // result == 0 means not enough space in captureOffsets; should never happen
1203 Q_ASSERT(result != 0);
1204
1205 if (result > 0) {
1206 // full match
1207 priv->isValid = true;
1208 priv->hasMatch = true;
1209 priv->capturedCount = result;
1210 priv->capturedOffsets.resize(result * 2);
1211 } else {
1212 // no match, partial match or error
1213 priv->hasPartialMatch = (result == PCRE2_ERROR_PARTIAL);
1214 priv->isValid = (result == PCRE2_ERROR_NOMATCH || result == PCRE2_ERROR_PARTIAL);
1215
1216 if (result == PCRE2_ERROR_PARTIAL) {
1217 // partial match:
1218 // leave the start and end capture offsets (i.e. cap(0))
1219 priv->capturedCount = 1;
1220 priv->capturedOffsets.resize(2);
1221 } else {
1222 // no match or error
1223 priv->capturedCount = 0;
1224 priv->capturedOffsets.clear();
1225 }
1226 }
1227
1228 // copy the captured substrings offsets, if any
1229 if (priv->capturedCount) {
1230 PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_16(matchData);
1231 qsizetype *const capturedOffsets = priv->capturedOffsets.data();
1232
1233 // We rely on the fact that capturing groups that did not
1234 // capture anything have offset -1, but PCRE technically
1235 // returns "PCRE2_UNSET". Test that out, better safe than
1236 // sorry...
1237 static_assert(qsizetype(PCRE2_UNSET) == qsizetype(-1), "Internal error: PCRE2 changed its API");
1238
1239 for (int i = 0; i < priv->capturedCount * 2; ++i)
1240 capturedOffsets[i] = qsizetype(ovector[i]);
1241
1242 // For partial matches, PCRE2 and PCRE1 differ in behavior when lookbehinds
1243 // are involved. PCRE2 reports the real begin of the match and the maximum
1244 // used lookbehind as distinct information; PCRE1 instead automatically
1245 // adjusted ovector[0] to include the maximum lookbehind.
1246 //
1247 // For instance, given the pattern "\bstring\b", and the subject "a str":
1248 // * PCRE1 reports partial, capturing " str"
1249 // * PCRE2 reports partial, capturing "str" with a lookbehind of 1
1250 //
1251 // To keep behavior, emulate PCRE1 here.
1252 // (Eventually, we could expose the lookbehind info in a future patch.)
1253 if (result == PCRE2_ERROR_PARTIAL) {
1254 unsigned int maximumLookBehind;
1255 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_MAXLOOKBEHIND, &maximumLookBehind);
1256 capturedOffsets[0] -= maximumLookBehind;
1257 }
1258 }
1259
1260 pcre2_match_data_free_16(matchData);
1261 pcre2_match_context_free_16(matchContext);
1262}
1263
1268 const QString &subjectStorage,
1269 QStringView subject,
1271 QRegularExpression::MatchOptions matchOptions)
1272 : regularExpression(re),
1273 subjectStorage(subjectStorage),
1274 subject(subject),
1275 matchType(matchType),
1276 matchOptions(matchOptions)
1277{
1278}
1279
1284{
1287
1290 subject,
1291 matchType,
1292 matchOptions);
1293
1294 // Note the DontCheckSubjectString passed for the check of the subject string:
1295 // if we're advancing a match on the same subject,
1296 // then that subject was already checked at least once (when this object
1297 // was created, or when the object that created this one was created, etc.)
1298 regularExpression.d->doMatch(nextPrivate,
1301 this);
1302 return QRegularExpressionMatch(*nextPrivate);
1303}
1304
1310 QRegularExpression::MatchOptions matchOptions,
1312 : next(next),
1313 regularExpression(re),
1314 matchType(matchType), matchOptions(matchOptions)
1315{
1316}
1317
1322{
1323 return next.isValid() && (next.hasMatch() || next.hasPartialMatch());
1324}
1325
1326// PUBLIC API
1327
1336{
1337}
1338
1347{
1348 d->pattern = pattern;
1349 d->patternOptions = options;
1350}
1351
1358
1377{
1378}
1379
1381
1382
1387
1401{
1402 return d->pattern;
1403}
1404
1412{
1413 if (d->pattern == pattern)
1414 return;
1415 d.detach();
1416 d->isDirty = true;
1417 d->pattern = pattern;
1418}
1419
1425QRegularExpression::PatternOptions QRegularExpression::patternOptions() const
1426{
1427 return d->patternOptions;
1428}
1429
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
1454{
1455 if (!isValid()) // will compile the pattern
1456 return -1;
1457 return d->capturingCount;
1458}
1459
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
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] = QString::fromUtf16(currentNamedCapturingTableRow + 1);
1512 }
1513
1514 return result;
1515}
1516
1525{
1526 d.data()->compilePattern();
1527 return d->compiledPattern;
1528}
1529
1537{
1538 d.data()->compilePattern();
1539 if (d->errorCode) {
1541 int errorStringLength;
1542 do {
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(errorStringLength);
1549
1550#ifdef QT_NO_TRANSLATION
1551 return errorString;
1552#else
1553 return QCoreApplication::translate("QRegularExpression", 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("QRegularExpression", "no error");
1560#endif
1561}
1562
1571{
1572 d.data()->compilePattern();
1573 return d->errorOffset;
1574}
1575
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);
1599}
1600
1601#if QT_DEPRECATED_SINCE(6, 8)
1611 MatchType matchType,
1612 MatchOptions matchOptions) const
1613{
1614 return matchView(subjectView, offset, matchType, matchOptions);
1615}
1616#endif // QT_DEPRECATED_SINCE(6, 8)
1617
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);
1647}
1648
1662 MatchType matchType,
1663 MatchOptions matchOptions) const
1664{
1667 matchType,
1668 matchOptions,
1669 match(subject, offset, matchType, matchOptions));
1670
1672}
1673
1674#if QT_DEPRECATED_SINCE(6, 8)
1684 MatchType matchType,
1685 MatchOptions matchOptions) const
1686{
1687 return globalMatchView(subjectView, offset, matchType, matchOptions);
1688}
1689#endif // QT_DEPRECATED_SINCE(6, 8)
1690
1711 MatchType matchType,
1712 MatchOptions matchOptions) const
1713{
1716 matchType,
1717 matchOptions,
1718 matchView(subjectView, offset, matchType, matchOptions));
1719
1721}
1722
1732{
1733 d.data()->compilePattern();
1734}
1735
1744{
1745 return (d == re.d) ||
1746 (d->pattern == re.d->pattern && d->patternOptions == re.d->patternOptions);
1747}
1748
1776size_t qHash(const QRegularExpression &key, size_t seed) noexcept
1777{
1778 return qHashMulti(seed, key.d->pattern, key.d->patternOptions);
1779}
1780
1807{
1809 const qsizetype count = str.size();
1810 result.reserve(count * 2);
1811
1812 // everything but [a-zA-Z0-9_] gets escaped,
1813 // cf. perldoc -f quotemeta
1814 for (qsizetype i = 0; i < count; ++i) {
1815 const QChar current = str.at(i);
1816
1817 if (current == QChar::Null) {
1818 // unlike Perl, a literal NUL must be escaped with
1819 // "\\0" (backslash + 0) and not "\\\0" (backslash + NUL),
1820 // because pcre16_compile uses a NUL-terminated string
1821 result.append(u'\\');
1822 result.append(u'0');
1823 } else if ((current < u'a' || current > u'z') &&
1824 (current < u'A' || current > u'Z') &&
1825 (current < u'0' || current > u'9') &&
1826 current != u'_') {
1827 result.append(u'\\');
1828 result.append(current);
1829 if (current.isHighSurrogate() && i < (count - 1))
1830 result.append(str.at(++i));
1831 } else {
1832 result.append(current);
1833 }
1834 }
1835
1836 result.squeeze();
1837 return result;
1838}
1839
1929{
1930 const qsizetype wclen = pattern.size();
1931 QString rx;
1932 rx.reserve(wclen + wclen / 16);
1933 qsizetype i = 0;
1934 const QChar *wc = pattern.data();
1935
1936 struct GlobSettings {
1937 char16_t nativePathSeparator;
1938 QStringView starEscape;
1939 QStringView questionMarkEscape;
1940 };
1941
1942 const GlobSettings settings = [options]() {
1943 if (options.testFlag(NonPathWildcardConversion)) {
1944 // using [\d\D] to mean "match everything";
1945 // dot doesn't match newlines, unless in /s mode
1946 return GlobSettings{ u'\0', u"[\\d\\D]*", u"[\\d\\D]" };
1947 } else {
1948#ifdef Q_OS_WIN
1949 return GlobSettings{ u'\\', u"[^/\\\\]*", u"[^/\\\\]" };
1950#else
1951 return GlobSettings{ u'/', u"[^/]*", u"[^/]" };
1952#endif
1953 }
1954 }();
1955
1956 while (i < wclen) {
1957 const QChar c = wc[i++];
1958 switch (c.unicode()) {
1959 case '*':
1960 rx += settings.starEscape;
1961 break;
1962 case '?':
1963 rx += settings.questionMarkEscape;
1964 break;
1965 // When not using filepath globbing: \ is escaped, / is itself
1966 // When using filepath globbing:
1967 // * Unix: \ gets escaped. / is itself
1968 // * Windows: \ and / can match each other -- they become [/\\] in regexp
1969 case '\\':
1970#ifdef Q_OS_WIN
1971 if (options.testFlag(NonPathWildcardConversion))
1972 rx += u"\\\\";
1973 else
1974 rx += u"[/\\\\]";
1975 break;
1976 case '/':
1977 if (options.testFlag(NonPathWildcardConversion))
1978 rx += u'/';
1979 else
1980 rx += u"[/\\\\]";
1981 break;
1982#endif
1983 case '$':
1984 case '(':
1985 case ')':
1986 case '+':
1987 case '.':
1988 case '^':
1989 case '{':
1990 case '|':
1991 case '}':
1992 rx += u'\\';
1993 rx += c;
1994 break;
1995 case '[':
1996 rx += c;
1997 // Support for the [!abc] or [!a-c] syntax
1998 if (i < wclen) {
1999 if (wc[i] == u'!') {
2000 rx += u'^';
2001 ++i;
2002 }
2003
2004 if (i < wclen && wc[i] == u']')
2005 rx += wc[i++];
2006
2007 while (i < wclen && wc[i] != u']') {
2008 if (!options.testFlag(NonPathWildcardConversion)) {
2009 // The '/' appearing in a character class invalidates the
2010 // regular expression parsing. It also concerns '\\' on
2011 // Windows OS types.
2012 if (wc[i] == u'/' || wc[i] == settings.nativePathSeparator)
2013 return rx;
2014 }
2015 if (wc[i] == u'\\')
2016 rx += u'\\';
2017 rx += wc[i++];
2018 }
2019 }
2020 break;
2021 default:
2022 rx += c;
2023 break;
2024 }
2025 }
2026
2027 if (!(options & UnanchoredWildcardConversion))
2029
2030 return rx;
2031}
2032
2047 WildcardConversionOptions options)
2048{
2051 return QRegularExpression(wildcardToRegularExpression(pattern, options), reOptions);
2052}
2053
2067{
2068 return QString()
2069 + "\\A(?:"_L1
2070 + expression
2071 + ")\\z"_L1;
2072}
2073
2087 QString(),
2088 QStringView(),
2089 QRegularExpression::NoMatch,
2090 QRegularExpression::NoMatchOption))
2091{
2092 d->isValid = true;
2093}
2094
2099{
2100}
2101
2103
2104
2110 : d(match.d)
2111{
2112}
2113
2133{
2134 d = match.d;
2135 return *this;
2136}
2137
2160 : d(&dd)
2161{
2162}
2163
2171{
2172 return d->regularExpression;
2173}
2174
2175
2184{
2185 return d->matchType;
2186}
2187
2195QRegularExpression::MatchOptions QRegularExpressionMatch::matchOptions() const
2196{
2197 return d->matchOptions;
2198}
2199
2215{
2216 return d->capturedCount - 1;
2217}
2218
2241{
2242 const int nth = d->regularExpression.d->captureIndexForName(name);
2243 return hasCaptured(nth);
2244}
2245
2269{
2270 if (nth < 0 || nth > lastCapturedIndex())
2271 return false;
2272
2273 return d->capturedOffsets.at(nth * 2) != -1;
2274}
2275
2289{
2290 return capturedView(nth).toString();
2291}
2292
2308{
2309 if (!hasCaptured(nth))
2310 return QStringView();
2311
2313
2314 if (start == -1) // didn't capture
2315 return QStringView();
2316
2317 return d->subject.mid(start, capturedLength(nth));
2318}
2319
2343{
2344 if (name.isEmpty()) {
2345 qWarning("QRegularExpressionMatch::captured: empty capturing group name passed");
2346 return QString();
2347 }
2348
2349 return capturedView(name).toString();
2350}
2351
2365{
2366 if (name.isEmpty()) {
2367 qWarning("QRegularExpressionMatch::capturedView: empty capturing group name passed");
2368 return QStringView();
2369 }
2371 if (nth == -1)
2372 return QStringView();
2373 return capturedView(nth);
2374}
2375
2383{
2384 QStringList texts;
2385 texts.reserve(d->capturedCount);
2386 for (int i = 0; i < d->capturedCount; ++i)
2387 texts << captured(i);
2388 return texts;
2389}
2390
2400{
2401 if (!hasCaptured(nth))
2402 return -1;
2403
2404 return d->capturedOffsets.at(nth * 2);
2405}
2406
2416{
2417 // bound checking performed by these two functions
2418 return capturedEnd(nth) - capturedStart(nth);
2419}
2420
2429{
2430 if (!hasCaptured(nth))
2431 return -1;
2432
2433 return d->capturedOffsets.at(nth * 2 + 1);
2434}
2435
2478{
2479 if (name.isEmpty()) {
2480 qWarning("QRegularExpressionMatch::capturedStart: empty capturing group name passed");
2481 return -1;
2482 }
2484 if (nth == -1)
2485 return -1;
2486 return capturedStart(nth);
2487}
2488
2501{
2502 if (name.isEmpty()) {
2503 qWarning("QRegularExpressionMatch::capturedLength: empty capturing group name passed");
2504 return 0;
2505 }
2507 if (nth == -1)
2508 return 0;
2509 return capturedLength(nth);
2510}
2511
2523{
2524 if (name.isEmpty()) {
2525 qWarning("QRegularExpressionMatch::capturedEnd: empty capturing group name passed");
2526 return -1;
2527 }
2529 if (nth == -1)
2530 return -1;
2531 return capturedEnd(nth);
2532}
2533
2541{
2542 return d->hasMatch;
2543}
2544
2556{
2557 return d->hasPartialMatch;
2558}
2559
2568{
2569 return d->isValid;
2570}
2571
2576 : d(&dd)
2577{
2578}
2579
2594 QRegularExpression::NoMatch,
2595 QRegularExpression::NoMatchOption,
2597{
2598}
2599
2604{
2605}
2606
2608
2609
2616 : d(iterator.d)
2617{
2618}
2619
2639{
2640 d = iterator.d;
2641 return *this;
2642}
2643
2671{
2672 return d->next.isValid();
2673}
2674
2682{
2683 return d->hasNext();
2684}
2685
2693{
2694 if (!hasNext())
2695 qWarning("QRegularExpressionMatchIterator::peekNext() called on an iterator already at end");
2696
2697 return d->next;
2698}
2699
2707{
2708 if (!hasNext()) {
2709 qWarning("QRegularExpressionMatchIterator::next() called on an iterator already at end");
2710 return d.constData()->next;
2711 }
2712
2713 d.detach();
2714 return std::exchange(d->next, d->next.d.constData()->nextMatch());
2715}
2716
2724{
2725 return d->regularExpression;
2726}
2727
2736{
2737 return d->matchType;
2738}
2739
2747QRegularExpression::MatchOptions QRegularExpressionMatchIterator::matchOptions() const
2748{
2749 return d->matchOptions;
2750}
2751
2756{
2758}
2759
2765#ifndef QT_NO_DATASTREAM
2774{
2775 out << re.pattern() << quint32(re.patternOptions().toInt());
2776 return out;
2777}
2778
2787{
2789 quint32 patternOptions;
2790 in >> pattern >> patternOptions;
2791 re.setPattern(pattern);
2792 re.setPatternOptions(QRegularExpression::PatternOptions::fromInt(patternOptions));
2793 return in;
2794}
2795#endif
2796
2797#ifndef QT_NO_DEBUG_STREAM
2807{
2808 QDebugStateSaver saver(debug);
2809 debug.nospace() << "QRegularExpression(" << re.pattern() << ", " << re.patternOptions() << ')';
2810 return debug;
2811}
2812
2821QDebug operator<<(QDebug debug, QRegularExpression::PatternOptions patternOptions)
2822{
2823 QDebugStateSaver saver(debug);
2825
2826 if (patternOptions == QRegularExpression::NoPatternOption) {
2827 flags = "NoPatternOption";
2828 } else {
2829 flags.reserve(200); // worst case...
2830 if (patternOptions & QRegularExpression::CaseInsensitiveOption)
2831 flags.append("CaseInsensitiveOption|");
2833 flags.append("DotMatchesEverythingOption|");
2834 if (patternOptions & QRegularExpression::MultilineOption)
2835 flags.append("MultilineOption|");
2837 flags.append("ExtendedPatternSyntaxOption|");
2839 flags.append("InvertedGreedinessOption|");
2840 if (patternOptions & QRegularExpression::DontCaptureOption)
2841 flags.append("DontCaptureOption|");
2843 flags.append("UseUnicodePropertiesOption|");
2844 flags.chop(1);
2845 }
2846
2847 debug.nospace() << "QRegularExpression::PatternOptions(" << flags << ')';
2848
2849 return debug;
2850}
2860{
2861 QDebugStateSaver saver(debug);
2862 debug.nospace() << "QRegularExpressionMatch(";
2863
2864 if (!match.isValid()) {
2865 debug << "Invalid)";
2866 return debug;
2867 }
2868
2869 debug << "Valid";
2870
2871 if (match.hasMatch()) {
2872 debug << ", has match: ";
2873 for (int i = 0; i <= match.lastCapturedIndex(); ++i) {
2874 debug << i
2875 << ":(" << match.capturedStart(i) << ", " << match.capturedEnd(i)
2876 << ", " << match.captured(i) << ')';
2877 if (i < match.lastCapturedIndex())
2878 debug << ", ";
2879 }
2880 } else if (match.hasPartialMatch()) {
2881 debug << ", has partial match: ("
2882 << match.capturedStart(0) << ", "
2883 << match.capturedEnd(0) << ", "
2884 << match.captured(0) << ')';
2885 } else {
2886 debug << ", no match";
2887 }
2888
2889 debug << ')';
2890
2891 return debug;
2892}
2893#endif
2894
2895// fool lupdate: make it extract those strings for translation, but don't put them
2896// inside Qt -- they're already inside libpcre (cf. man 3 pcreapi, pcre_compile.c).
2897#if 0
2898
2899/* PCRE is a library of functions to support regular expressions whose syntax
2900and semantics are as close as possible to those of the Perl 5 language.
2901
2902 Written by Philip Hazel
2903 Original API code Copyright (c) 1997-2012 University of Cambridge
2904 New API code Copyright (c) 2015 University of Cambridge
2905
2906-----------------------------------------------------------------------------
2907Redistribution and use in source and binary forms, with or without
2908modification, are permitted provided that the following conditions are met:
2909
2910 * Redistributions of source code must retain the above copyright notice,
2911 this list of conditions and the following disclaimer.
2912
2913 * Redistributions in binary form must reproduce the above copyright
2914 notice, this list of conditions and the following disclaimer in the
2915 documentation and/or other materials provided with the distribution.
2916
2917 * Neither the name of the University of Cambridge nor the names of its
2918 contributors may be used to endorse or promote products derived from
2919 this software without specific prior written permission.
2920
2921THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2922AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2923IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2924ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2925LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2926CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2927SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2928INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2929CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2930ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2931POSSIBILITY OF SUCH DAMAGE.
2932-----------------------------------------------------------------------------
2933*/
2934
2935static const char *pcreCompileErrorCodes[] =
2936{
2937 QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
2938 QT_TRANSLATE_NOOP("QRegularExpression", "\\ at end of pattern"),
2939 QT_TRANSLATE_NOOP("QRegularExpression", "\\c at end of pattern"),
2940 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character follows \\"),
2941 QT_TRANSLATE_NOOP("QRegularExpression", "numbers out of order in {} quantifier"),
2942 QT_TRANSLATE_NOOP("QRegularExpression", "number too big in {} quantifier"),
2943 QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating ] for character class"),
2944 QT_TRANSLATE_NOOP("QRegularExpression", "escape sequence is invalid in character class"),
2945 QT_TRANSLATE_NOOP("QRegularExpression", "range out of order in character class"),
2946 QT_TRANSLATE_NOOP("QRegularExpression", "quantifier does not follow a repeatable item"),
2947 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unexpected repeat"),
2948 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (? or (?-"),
2949 QT_TRANSLATE_NOOP("QRegularExpression", "POSIX named classes are supported only within a class"),
2950 QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
2951 QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis"),
2952 QT_TRANSLATE_NOOP("QRegularExpression", "reference to non-existent subpattern"),
2953 QT_TRANSLATE_NOOP("QRegularExpression", "pattern passed as NULL"),
2954 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognised compile-time option bit(s)"),
2955 QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after (?# comment"),
2956 QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
2957 QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too large"),
2958 QT_TRANSLATE_NOOP("QRegularExpression", "failed to allocate heap memory"),
2959 QT_TRANSLATE_NOOP("QRegularExpression", "unmatched closing parenthesis"),
2960 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: code overflow"),
2961 QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis for condition"),
2962 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is not fixed length"),
2963 QT_TRANSLATE_NOOP("QRegularExpression", "a relative value of zero is not allowed"),
2964 QT_TRANSLATE_NOOP("QRegularExpression", "conditional subpattern contains more than two branches"),
2965 QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?( or (?(?C)"),
2966 QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+ or (?-"),
2967 QT_TRANSLATE_NOOP("QRegularExpression", "unknown POSIX class name"),
2968 QT_TRANSLATE_NOOP("QRegularExpression", "internal error in pcre2_study(): should not occur"),
2969 QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have Unicode support"),
2970 QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"),
2971 QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\x{} or \\o{} is too large"),
2972 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind is too complicated"),
2973 QT_TRANSLATE_NOOP("QRegularExpression", "\\C is not allowed in a lookbehind assertion in UTF-" "16" " mode"),
2974 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2 does not support \\F, \\L, \\l, \\N{name}, \\U, or \\u"),
2975 QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is greater than 255"),
2976 QT_TRANSLATE_NOOP("QRegularExpression", "closing parenthesis for (?C expected"),
2977 QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in (*VERB) name"),
2978 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?P"),
2979 QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in subpattern name (missing terminator?)"),
2980 QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name (PCRE2_DUPNAMES not set)"),
2981 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name must start with a non-digit"),
2982 QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have support for \\P, \\p, or \\X"),
2983 QT_TRANSLATE_NOOP("QRegularExpression", "malformed \\P or \\p sequence"),
2984 QT_TRANSLATE_NOOP("QRegularExpression", "unknown property name after \\P or \\p"),
2985 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum " "32" " code units)"),
2986 QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum " "10000" ")"),
2987 QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"),
2988 QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 in 8-bit non-UTF-8 mode"),
2989 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: overran compiling workspace"),
2990 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: previously-checked referenced subpattern not found"),
2991 QT_TRANSLATE_NOOP("QRegularExpression", "DEFINE subpattern contains more than one branch"),
2992 QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"),
2993 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown newline setting"),
2994 QT_TRANSLATE_NOOP("QRegularExpression", "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number"),
2995 QT_TRANSLATE_NOOP("QRegularExpression", "(?R (recursive pattern call) must be followed by a closing parenthesis"),
2996 QT_TRANSLATE_NOOP("QRegularExpression", "obsolete error (should not occur)"),
2997 QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized or malformed"),
2998 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern number is too big"),
2999 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name expected"),
3000 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: parsed pattern overflow"),
3001 QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"),
3002 QT_TRANSLATE_NOOP("QRegularExpression", "different names for subpatterns of the same number are not allowed"),
3003 QT_TRANSLATE_NOOP("QRegularExpression", "(*MARK) must have an argument"),
3004 QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
3005 QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a printable ASCII character"),
3006 QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a letter or one of [\\]^_?"),
3007 QT_TRANSLATE_NOOP("QRegularExpression", "\\k is not followed by a braced, angle-bracketed, or quoted name"),
3008 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown meta code in check_lookbehinds()"),
3009 QT_TRANSLATE_NOOP("QRegularExpression", "\\N is not supported in a class"),
3010 QT_TRANSLATE_NOOP("QRegularExpression", "callout string is too long"),
3011 QT_TRANSLATE_NOOP("QRegularExpression", "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)"),
3012 QT_TRANSLATE_NOOP("QRegularExpression", "using UTF is disabled by the application"),
3013 QT_TRANSLATE_NOOP("QRegularExpression", "using UCP is disabled by the application"),
3014 QT_TRANSLATE_NOOP("QRegularExpression", "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)"),
3015 QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\u.... sequence is too large"),
3016 QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{} or \\N{U+}"),
3017 QT_TRANSLATE_NOOP("QRegularExpression", "syntax error or number too big in (?(VERSION condition"),
3018 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in auto_possessify()"),
3019 QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating delimiter for callout with string argument"),
3020 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized string delimiter follows (?C"),
3021 QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled by the application"),
3022 QT_TRANSLATE_NOOP("QRegularExpression", "(?| and/or (?J: or (?x: parentheses are too deeply nested"),
3023 QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled in this PCRE2 library"),
3024 QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too complicated"),
3025 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is too long"),
3026 QT_TRANSLATE_NOOP("QRegularExpression", "pattern string is longer than the limit set by the application"),
3027 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown code in parsed pattern"),
3028 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: bad code value in parsed_skip()"),
3029 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode"),
3030 QT_TRANSLATE_NOOP("QRegularExpression", "invalid option bits with PCRE2_LITERAL"),
3031 QT_TRANSLATE_NOOP("QRegularExpression", "\\N{U+dddd} is supported only in Unicode (UTF) mode"),
3032 QT_TRANSLATE_NOOP("QRegularExpression", "invalid hyphen in option setting"),
3033 QT_TRANSLATE_NOOP("QRegularExpression", "(*alpha_assertion) not recognized"),
3034 QT_TRANSLATE_NOOP("QRegularExpression", "script runs require Unicode support, which this version of PCRE2 does not have"),
3035 QT_TRANSLATE_NOOP("QRegularExpression", "too many capturing groups (maximum 65535)"),
3036 QT_TRANSLATE_NOOP("QRegularExpression", "atomic assertion expected after (?( or (?(?C)"),
3037 QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
3038 QT_TRANSLATE_NOOP("QRegularExpression", "no match"),
3039 QT_TRANSLATE_NOOP("QRegularExpression", "partial match"),
3040 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 1 byte missing at end"),
3041 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 2 bytes missing at end"),
3042 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 3 bytes missing at end"),
3043 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 4 bytes missing at end"),
3044 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5 bytes missing at end"),
3045 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 2 top bits not 0x80"),
3046 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 3 top bits not 0x80"),
3047 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 4 top bits not 0x80"),
3048 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 5 top bits not 0x80"),
3049 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 6 top bits not 0x80"),
3050 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5-byte character is not allowed (RFC 3629)"),
3051 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 6-byte character is not allowed (RFC 3629)"),
3052 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points greater than 0x10ffff are not defined"),
3053 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points 0xd800-0xdfff are not defined"),
3054 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 2-byte sequence"),
3055 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 3-byte sequence"),
3056 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 4-byte sequence"),
3057 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 5-byte sequence"),
3058 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 6-byte sequence"),
3059 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: isolated byte with 0x80 bit set"),
3060 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: illegal byte (0xfe or 0xff)"),
3061 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: missing low surrogate at end"),
3062 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: invalid low surrogate"),
3063 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: isolated low surrogate"),
3064 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points 0xd800-0xdfff are not defined"),
3065 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points greater than 0x10ffff are not defined"),
3066 QT_TRANSLATE_NOOP("QRegularExpression", "bad data value"),
3067 QT_TRANSLATE_NOOP("QRegularExpression", "patterns do not all use the same character tables"),
3068 QT_TRANSLATE_NOOP("QRegularExpression", "magic number missing"),
3069 QT_TRANSLATE_NOOP("QRegularExpression", "pattern compiled in wrong mode: 8/16/32-bit error"),
3070 QT_TRANSLATE_NOOP("QRegularExpression", "bad offset value"),
3071 QT_TRANSLATE_NOOP("QRegularExpression", "bad option value"),
3072 QT_TRANSLATE_NOOP("QRegularExpression", "invalid replacement string"),
3073 QT_TRANSLATE_NOOP("QRegularExpression", "bad offset into UTF string"),
3074 QT_TRANSLATE_NOOP("QRegularExpression", "callout error code"),
3075 QT_TRANSLATE_NOOP("QRegularExpression", "invalid data in workspace for DFA restart"),
3076 QT_TRANSLATE_NOOP("QRegularExpression", "too much recursion for DFA matching"),
3077 QT_TRANSLATE_NOOP("QRegularExpression", "backreference condition or recursion test is not supported for DFA matching"),
3078 QT_TRANSLATE_NOOP("QRegularExpression", "function is not supported for DFA matching"),
3079 QT_TRANSLATE_NOOP("QRegularExpression", "pattern contains an item that is not supported for DFA matching"),
3080 QT_TRANSLATE_NOOP("QRegularExpression", "workspace size exceeded in DFA matching"),
3081 QT_TRANSLATE_NOOP("QRegularExpression", "internal error - pattern overwritten?"),
3082 QT_TRANSLATE_NOOP("QRegularExpression", "bad JIT option"),
3083 QT_TRANSLATE_NOOP("QRegularExpression", "JIT stack limit reached"),
3084 QT_TRANSLATE_NOOP("QRegularExpression", "match limit exceeded"),
3085 QT_TRANSLATE_NOOP("QRegularExpression", "no more memory"),
3086 QT_TRANSLATE_NOOP("QRegularExpression", "unknown substring"),
3087 QT_TRANSLATE_NOOP("QRegularExpression", "non-unique substring name"),
3088 QT_TRANSLATE_NOOP("QRegularExpression", "NULL argument passed"),
3089 QT_TRANSLATE_NOOP("QRegularExpression", "nested recursion at the same subject position"),
3090 QT_TRANSLATE_NOOP("QRegularExpression", "matching depth limit exceeded"),
3091 QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not available"),
3092 QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not set"),
3093 QT_TRANSLATE_NOOP("QRegularExpression", "offset limit set without PCRE2_USE_OFFSET_LIMIT"),
3094 QT_TRANSLATE_NOOP("QRegularExpression", "bad escape sequence in replacement string"),
3095 QT_TRANSLATE_NOOP("QRegularExpression", "expected closing curly bracket in replacement string"),
3096 QT_TRANSLATE_NOOP("QRegularExpression", "bad substitution in replacement string"),
3097 QT_TRANSLATE_NOOP("QRegularExpression", "match with end before start or start moved backwards is not supported"),
3098 QT_TRANSLATE_NOOP("QRegularExpression", "too many replacements (more than INT_MAX)"),
3099 QT_TRANSLATE_NOOP("QRegularExpression", "bad serialized data"),
3100 QT_TRANSLATE_NOOP("QRegularExpression", "heap limit exceeded"),
3101 QT_TRANSLATE_NOOP("QRegularExpression", "invalid syntax"),
3102 QT_TRANSLATE_NOOP("QRegularExpression", "internal error - duplicate substitution match"),
3103 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching")
3104};
3105#endif // #if 0
3106
\inmodule QtCore
Definition qbytearray.h:57
int toInt(bool *ok=nullptr, int base=10) const
Returns the byte array converted to an int using base base, which is ten by default.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
\inmodule QtCore
Definition qchar.h:48
@ Null
Definition qchar.h:51
constexpr bool isLowSurrogate() const noexcept
Returns true if the QChar is the low part of a UTF16 surrogate (for example if its code point is in r...
Definition qchar.h:480
constexpr bool isHighSurrogate() const noexcept
Returns true if the QChar is the high part of a UTF16 surrogate (for example if its code point is in ...
Definition qchar.h:479
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore\reentrant
Definition qdatastream.h:30
\inmodule QtCore
\inmodule QtCore
void detach()
If the shared data object's reference count is greater than 1, this function creates a deep copy of t...
T * data() const noexcept
Returns a pointer to the shared data object.
const T * constData() const noexcept
Returns a const pointer to the shared data object.
Definition qlist.h:74
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qmutex.h:285
\inmodule QtCore \reentrant
QRegularExpressionMatch next()
Returns the next match result and advances the iterator by one position.
QRegularExpressionMatchIterator & operator=(const QRegularExpressionMatchIterator &iterator)
Assigns the iterator iterator to this object, and returns a reference to the copy.
bool isValid() const
Returns true if the iterator object was obtained as a result from the QRegularExpression::globalMatch...
~QRegularExpressionMatchIterator()
Destroys the QRegularExpressionMatchIterator object.
QRegularExpression::MatchOptions matchOptions() const
Returns the match options that were used to get this QRegularExpressionMatchIterator object,...
QRegularExpressionMatch peekNext() const
Returns the next match result without moving the iterator.
bool hasNext() const
Returns true if there is at least one match result ahead of the iterator; otherwise it returns false.
QRegularExpression::MatchType matchType() const
Returns the match type that was used to get this QRegularExpressionMatchIterator object,...
QRegularExpression regularExpression() const
Returns the QRegularExpression object whose globalMatch() function returned this object.
\inmodule QtCore \reentrant
QRegularExpression::MatchOptions matchOptions() const
Returns the match options that were used to get this QRegularExpressionMatch object,...
QStringView capturedView(int nth=0) const
qsizetype capturedEnd(int nth=0) const
Returns the offset inside the subject string immediately after the ending position of the substring c...
QRegularExpression::MatchType matchType() const
Returns the match type that was used to get this QRegularExpressionMatch object, that is,...
~QRegularExpressionMatch()
Destroys the match result.
bool hasPartialMatch() const
Returns true if the regular expression partially matched against the subject string,...
bool hasCaptured(const QString &name) const
bool isValid() const
Returns true if the match object was obtained as a result from the QRegularExpression::match() functi...
bool hasMatch() const
Returns true if the regular expression matched against the subject string, or false otherwise.
QStringList capturedTexts() const
Returns a list of all strings captured by capturing groups, in the order the groups themselves appear...
qsizetype capturedStart(int nth=0) const
Returns the offset inside the subject string corresponding to the starting position of the substring ...
qsizetype capturedLength(int nth=0) const
Returns the length of the substring captured by the nth capturing group.
int lastCapturedIndex() const
Returns the index of the last capturing group that captured something, including the implicit capturi...
QRegularExpressionMatch & operator=(const QRegularExpressionMatch &match)
Assigns the match result match to this object, and returns a reference to the copy.
QString captured(int nth=0) const
Returns the substring captured by the nth capturing group.
QRegularExpression regularExpression() const
Returns the QRegularExpression object whose match() function returned this object.
QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match)
Writes the match object match into the debug object debug for debugging purposes.
\inmodule QtCore \reentrant
~QRegularExpression()
Destroys the QRegularExpression object.
bool isValid() const
Returns true if the regular expression is a valid regular expression (that is, it contains no syntax ...
PatternOptions patternOptions() const
Returns the pattern options for the regular expression.
friend class QRegularExpressionMatch
void setPatternOptions(PatternOptions options)
Sets the given options as the pattern options of the regular expression.
int captureCount() const
Returns the number of capturing groups inside the pattern string, or -1 if the regular expression is ...
QDataStream & operator<<(QDataStream &out, const QRegularExpression &re)
Writes the regular expression re to stream out.
QRegularExpression & operator=(const QRegularExpression &re) noexcept
Assigns the regular expression re to this object, and returns a reference to the copy.
qsizetype patternErrorOffset() const
Returns the offset, inside the pattern string, at which an error was found when checking the validity...
static QString escape(const QString &str)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QDataStream & operator>>(QDataStream &in, QRegularExpression &re)
Reads a regular expression from stream in into re.
static QRegularExpression fromWildcard(QStringView pattern, Qt::CaseSensitivity cs=Qt::CaseInsensitive, WildcardConversionOptions options=DefaultWildcardConversion)
void setPattern(const QString &pattern)
Sets the pattern string of the regular expression to pattern.
QStringList namedCaptureGroups() const
friend struct QRegularExpressionMatchPrivate
MatchType
The MatchType enum defines the type of the match that should be attempted against the subject string.
friend class QRegularExpressionMatchIterator
bool operator==(const QRegularExpression &re) const
Returns true if the regular expression is equal to re, or false otherwise.
QRegularExpressionMatch matchView(QStringView subjectView, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
QString pattern() const
Returns the pattern string of the regular expression.
QRegularExpressionMatch match(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
Attempts to match the regular expression against the given subject string, starting at the position o...
QDebug operator<<(QDebug debug, QRegularExpression::PatternOptions patternOptions)
Writes the pattern options patternOptions into the debug object debug for debugging purposes.
QRegularExpressionMatchIterator globalMatchView(QStringView subjectView, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
QString errorString() const
Returns a textual description of the error found when checking the validity of the regular expression...
QRegularExpressionMatchIterator globalMatch(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
Attempts to perform a global match of the regular expression against the given subject string,...
static QString anchoredPattern(const QString &expression)
static QString wildcardToRegularExpression(const QString &str, WildcardConversionOptions options=DefaultWildcardConversion)
QDebug operator<<(QDebug debug, const QRegularExpression &re)
Writes the regular expression re into the debug object debug for debugging purposes.
QRegularExpression()
Constructs a QRegularExpression object with an empty pattern and no pattern options.
\inmodule QtCore
Definition qshareddata.h:19
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1014
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromUtf16(const char16_t *, qsizetype size=-1)
Definition qstring.cpp:5883
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1095
void resize(qsizetype size)
Sets the size of the string to size characters.
Definition qstring.cpp:2654
QString str
[2]
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
CaseSensitivity
@ CaseSensitive
#define Q_UNLIKELY(x)
#define Q_DECL_COLD_FUNCTION
size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed=0)
constexpr QtPrivate::QHashMultiReturnType< T... > qHashMulti(size_t seed, const T &... args) noexcept(std::conjunction_v< QtPrivate::QNothrowHashable< T >... >)
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
static const QMetaObjectPrivate * priv(const uint *data)
GLuint64 key
GLuint index
[2]
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLbitfield flags
GLuint start
GLenum GLuint GLintptr offset
GLuint name
const GLubyte * c
GLuint in
GLuint64EXT * result
[6]
GLubyte * pattern
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static pcre2_jit_stack_16 * qtPcreCallback(void *)
static int convertToPcreOptions(QRegularExpression::PatternOptions patternOptions)
Q_DECL_COLD_FUNCTION void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *where)
static bool isJitEnabled()
static int safe_pcre2_match_16(const pcre2_code_16 *code, PCRE2_SPTR16 subject, qsizetype length, qsizetype startOffset, int options, pcre2_match_data_16 *matchData, pcre2_match_context_16 *matchContext)
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
#define QT_DEFINE_QESDP_SPECIALIZATION_DTOR(Class)
#define qUtf16Printable(string)
Definition qstring.h:1403
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
#define QT_TRANSLATE_NOOP(scope, x)
unsigned int quint32
Definition qtypes.h:45
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned short ushort
Definition qtypes.h:28
QSettings settings("MySoft", "Star Runner")
[0]
QTextStream out(stdout)
[7]
QObject::connect nullptr
QMutex mutex
[2]
QReadWriteLock lock
[0]
p rx()++
QSharedPointer< T > other(t)
[5]
QRegularExpressionMatchIteratorPrivate(const QRegularExpression &re, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions, const QRegularExpressionMatch &next)
const QRegularExpression::MatchOptions matchOptions
const QRegularExpression::MatchType matchType
QRegularExpressionMatchPrivate(const QRegularExpression &re, const QString &subjectStorage, QStringView subject, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions)
const QRegularExpression::MatchType matchType
const QRegularExpression::MatchOptions matchOptions
QRegularExpressionMatch nextMatch() const
const QRegularExpression regularExpression
int captureIndexForName(QStringView name) const
void doMatch(QRegularExpressionMatchPrivate *priv, qsizetype offset, CheckSubjectStringOption checkSubjectStringOption=CheckSubjectString, const QRegularExpressionMatchPrivate *previous=nullptr) const
QRegularExpression::PatternOptions patternOptions