Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
667static int convertToPcreOptions(QRegularExpression::PatternOptions patternOptions)
668{
669 int options = 0;
670
672 options |= PCRE2_CASELESS;
674 options |= PCRE2_DOTALL;
675 if (patternOptions & QRegularExpression::MultilineOption)
676 options |= PCRE2_MULTILINE;
678 options |= PCRE2_EXTENDED;
680 options |= PCRE2_UNGREEDY;
681 if (patternOptions & QRegularExpression::DontCaptureOption)
682 options |= PCRE2_NO_AUTO_CAPTURE;
684 options |= PCRE2_UCP;
685
686 return options;
687}
688
692static int convertToPcreOptions(QRegularExpression::MatchOptions matchOptions)
693{
694 int options = 0;
695
697 options |= PCRE2_ANCHORED;
699 options |= PCRE2_NO_UTF_CHECK;
700
701 return options;
702}
703
705{
709
711 void compilePattern();
712 void getPatternInfo();
713 void optimizePattern();
714
719
722 CheckSubjectStringOption checkSubjectStringOption = CheckSubjectString,
723 const QRegularExpressionMatchPrivate *previous = nullptr) const;
724
726
727 // sizeof(QSharedData) == 4, so start our members with an enum
728 QRegularExpression::PatternOptions patternOptions;
730
731 // *All* of the following members are managed while holding this mutex,
732 // except for isDirty which is set to true by QRegularExpression setters
733 // (right after a detach happened).
734 mutable QMutex mutex;
735
736 // The PCRE code pointer is reference-counted by the QRegularExpressionPrivate
737 // objects themselves; when the private is copied (i.e. a detach happened)
738 // it is set to nullptr
739 pcre2_code_16 *compiledPattern;
745};
746
748{
750 const QString &subjectStorage,
753 QRegularExpression::MatchOptions matchOptions);
754
756
758
759 // subject is what we match upon. If we've been asked to match over
760 // a QString, then subjectStorage is a copy of that string
761 // (so that it's kept alive by us)
764
766 const QRegularExpression::MatchOptions matchOptions;
767
768 // the capturedOffsets vector contains pairs of (start, end) positions
769 // for each captured substring
770 QList<qsizetype> capturedOffsets;
771
773
774 bool hasMatch = false;
775 bool hasPartialMatch = false;
776 bool isValid = false;
777};
778
792
802{
803 if (pattern.isValidUtf16()) {
804 qWarning("%s(): called on an invalid QRegularExpression object "
805 "(pattern is '%ls')", where, qUtf16Printable(pattern));
806 } else {
807 qWarning("%s(): called on an invalid QRegularExpression object", where);
808 }
809}
810
815 : d(&dd)
816{
817}
818
823 : QSharedData(),
824 patternOptions(),
825 pattern(),
826 mutex(),
827 compiledPattern(nullptr),
828 errorCode(0),
829 errorOffset(-1),
830 capturingCount(0),
831 usingCrLfNewlines(false),
832 isDirty(true)
833{
834}
835
843
855 patternOptions(other.patternOptions),
857 mutex(),
858 compiledPattern(nullptr),
859 errorCode(0),
860 errorOffset(-1),
861 capturingCount(0),
862 usingCrLfNewlines(false),
863 isDirty(true)
864{
865}
866
871{
872 pcre2_code_free_16(compiledPattern);
873 compiledPattern = nullptr;
874 errorCode = 0;
875 errorOffset = -1;
876 capturingCount = 0;
877 usingCrLfNewlines = false;
878}
879
884{
885 const QMutexLocker lock(&mutex);
886
887 if (!isDirty)
888 return;
889
890 isDirty = false;
892
894 options |= PCRE2_UTF;
895
896 PCRE2_SIZE patternErrorOffset;
897 compiledPattern = pcre2_compile_16(reinterpret_cast<PCRE2_SPTR16>(pattern.constData()),
898 pattern.size(),
899 options,
900 &errorCode,
901 &patternErrorOffset,
902 nullptr);
903
904 if (!compiledPattern) {
905 errorOffset = qsizetype(patternErrorOffset);
906 return;
907 } else {
908 // ignore whatever PCRE2 wrote into errorCode -- leave it to 0 to mean "no error"
909 errorCode = 0;
910 }
911
914}
915
920{
922
923 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_CAPTURECOUNT, &capturingCount);
924
925 // detect the settings for the newline
926 unsigned int patternNewlineSetting;
927 if (pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NEWLINE, &patternNewlineSetting) != 0) {
928 // no option was specified in the regexp, grab PCRE build defaults
929 pcre2_config_16(PCRE2_CONFIG_NEWLINE, &patternNewlineSetting);
930 }
931
932 usingCrLfNewlines = (patternNewlineSetting == PCRE2_NEWLINE_CRLF) ||
933 (patternNewlineSetting == PCRE2_NEWLINE_ANY) ||
934 (patternNewlineSetting == PCRE2_NEWLINE_ANYCRLF);
935
936 unsigned int hasJOptionChanged;
937 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_JCHANGED, &hasJOptionChanged);
938 if (Q_UNLIKELY(hasJOptionChanged)) {
939 qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%ls'\n is using the (?J) option; duplicate capturing group names are not supported by Qt",
941 }
942}
943
944
945/*
946 Simple "smartpointer" wrapper around a pcre2_jit_stack_16, to be used with
947 QThreadStorage.
948*/
949namespace {
950struct PcreJitStackFree
951{
952 void operator()(pcre2_jit_stack_16 *stack)
953 {
954 if (stack)
955 pcre2_jit_stack_free_16(stack);
956 }
957};
958Q_CONSTINIT static thread_local std::unique_ptr<pcre2_jit_stack_16, PcreJitStackFree> jitStacks;
959}
960
964static pcre2_jit_stack_16 *qtPcreCallback(void *)
965{
966 return jitStacks.get();
967}
968
972static bool isJitEnabled()
973{
974 QByteArray jitEnvironment = qgetenv("QT_ENABLE_REGEXP_JIT");
975 if (!jitEnvironment.isEmpty()) {
976 bool ok;
977 int enableJit = jitEnvironment.toInt(&ok);
978 return ok ? (enableJit != 0) : true;
979 }
980
981#ifdef QT_DEBUG
982 return false;
983#elif defined(Q_OS_MACOS)
984 return !qt_mac_runningUnderRosetta();
985#else
986 return true;
987#endif
988}
989
1000{
1002
1003 static const bool enableJit = isJitEnabled();
1004
1005 if (!enableJit)
1006 return;
1007
1008 pcre2_jit_compile_16(compiledPattern, PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_PARTIAL_HARD);
1009}
1010
1018{
1019 Q_ASSERT(!name.isEmpty());
1020
1021 if (!compiledPattern)
1022 return -1;
1023
1024 // See the other usages of pcre2_pattern_info_16 for more details about this
1025 PCRE2_SPTR16 *namedCapturingTable;
1026 unsigned int namedCapturingTableEntryCount;
1027 unsigned int namedCapturingTableEntrySize;
1028
1029 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
1030 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
1031 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
1032
1033 for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
1034 const auto currentNamedCapturingTableRow =
1035 reinterpret_cast<const char16_t *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
1036
1037 if (name == (currentNamedCapturingTableRow + 1)) {
1038 const int index = *currentNamedCapturingTableRow;
1039 return index;
1040 }
1041 }
1042
1043 return -1;
1044}
1045
1053static int safe_pcre2_match_16(const pcre2_code_16 *code,
1054 PCRE2_SPTR16 subject, qsizetype length,
1055 qsizetype startOffset, int options,
1056 pcre2_match_data_16 *matchData,
1057 pcre2_match_context_16 *matchContext)
1058{
1059 int result = pcre2_match_16(code, subject, length,
1060 startOffset, options, matchData, matchContext);
1061
1062 if (result == PCRE2_ERROR_JIT_STACKLIMIT && !jitStacks) {
1063 // The default JIT stack size in PCRE is 32K,
1064 // we allocate from 32K up to 512K.
1065 jitStacks.reset(pcre2_jit_stack_create_16(32 * 1024, 512 * 1024, NULL));
1066
1067 result = pcre2_match_16(code, subject, length,
1068 startOffset, options, matchData, matchContext);
1069 }
1070
1071 return result;
1072}
1073
1104 CheckSubjectStringOption checkSubjectStringOption,
1105 const QRegularExpressionMatchPrivate *previous) const
1106{
1107 Q_ASSERT(priv);
1108 Q_ASSERT(priv != previous);
1109
1110 const qsizetype subjectLength = priv->subject.size();
1111
1112 if (offset < 0)
1113 offset += subjectLength;
1114
1115 if (offset < 0 || offset > subjectLength)
1116 return;
1117
1119 qtWarnAboutInvalidRegularExpression(pattern, "QRegularExpressionPrivate::doMatch");
1120 return;
1121 }
1122
1123 // skip doing the actual matching if NoMatch type was requested
1124 if (priv->matchType == QRegularExpression::NoMatch) {
1125 priv->isValid = true;
1126 return;
1127 }
1128
1129 int pcreOptions = convertToPcreOptions(priv->matchOptions);
1130
1132 pcreOptions |= PCRE2_PARTIAL_SOFT;
1134 pcreOptions |= PCRE2_PARTIAL_HARD;
1135
1136 if (checkSubjectStringOption == DontCheckSubjectString)
1137 pcreOptions |= PCRE2_NO_UTF_CHECK;
1138
1139 bool previousMatchWasEmpty = false;
1140 if (previous && previous->hasMatch &&
1141 (previous->capturedOffsets.at(0) == previous->capturedOffsets.at(1))) {
1142 previousMatchWasEmpty = true;
1143 }
1144
1145 pcre2_match_context_16 *matchContext = pcre2_match_context_create_16(nullptr);
1146 pcre2_jit_stack_assign_16(matchContext, &qtPcreCallback, nullptr);
1147 pcre2_match_data_16 *matchData = pcre2_match_data_create_from_pattern_16(compiledPattern, nullptr);
1148
1149 // PCRE does not accept a null pointer as subject string, even if
1150 // its length is zero. We however allow it in input: a QStringView
1151 // subject may have data == nullptr. In this case, to keep PCRE
1152 // happy, pass a pointer to a dummy character.
1153 const char16_t dummySubject = 0;
1154 const char16_t * const subjectUtf16 = [&]()
1155 {
1156 const auto subjectUtf16 = priv->subject.utf16();
1157 if (subjectUtf16)
1158 return subjectUtf16;
1159 Q_ASSERT(subjectLength == 0);
1160 return &dummySubject;
1161 }();
1162
1163 int result;
1164
1165 if (!previousMatchWasEmpty) {
1167 reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), subjectLength,
1168 offset, pcreOptions,
1169 matchData, matchContext);
1170 } else {
1172 reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), subjectLength,
1173 offset, pcreOptions | PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED,
1174 matchData, matchContext);
1175
1176 if (result == PCRE2_ERROR_NOMATCH) {
1177 ++offset;
1178
1180 && offset < subjectLength
1181 && subjectUtf16[offset - 1] == u'\r'
1182 && subjectUtf16[offset] == u'\n') {
1183 ++offset;
1184 } else if (offset < subjectLength
1185 && QChar::isLowSurrogate(subjectUtf16[offset])) {
1186 ++offset;
1187 }
1188
1190 reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), subjectLength,
1191 offset, pcreOptions,
1192 matchData, matchContext);
1193 }
1194 }
1195
1196#ifdef QREGULAREXPRESSION_DEBUG
1197 qDebug() << "Matching" << pattern << "against" << subject
1198 << "offset" << offset
1199 << priv->matchType << priv->matchOptions << previousMatchWasEmpty
1200 << "result" << result;
1201#endif
1202
1203 // result == 0 means not enough space in captureOffsets; should never happen
1204 Q_ASSERT(result != 0);
1205
1206 if (result > 0) {
1207 // full match
1208 priv->isValid = true;
1209 priv->hasMatch = true;
1210 priv->capturedCount = result;
1211 priv->capturedOffsets.resize(result * 2);
1212 } else {
1213 // no match, partial match or error
1214 priv->hasPartialMatch = (result == PCRE2_ERROR_PARTIAL);
1215 priv->isValid = (result == PCRE2_ERROR_NOMATCH || result == PCRE2_ERROR_PARTIAL);
1216
1217 if (result == PCRE2_ERROR_PARTIAL) {
1218 // partial match:
1219 // leave the start and end capture offsets (i.e. cap(0))
1220 priv->capturedCount = 1;
1221 priv->capturedOffsets.resize(2);
1222 } else {
1223 // no match or error
1224 priv->capturedCount = 0;
1225 priv->capturedOffsets.clear();
1226 }
1227 }
1228
1229 // copy the captured substrings offsets, if any
1230 if (priv->capturedCount) {
1231 PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_16(matchData);
1232 qsizetype *const capturedOffsets = priv->capturedOffsets.data();
1233
1234 // We rely on the fact that capturing groups that did not
1235 // capture anything have offset -1, but PCRE technically
1236 // returns "PCRE2_UNSET". Test that out, better safe than
1237 // sorry...
1238 static_assert(qsizetype(PCRE2_UNSET) == qsizetype(-1), "Internal error: PCRE2 changed its API");
1239
1240 for (int i = 0; i < priv->capturedCount * 2; ++i)
1241 capturedOffsets[i] = qsizetype(ovector[i]);
1242
1243 // For partial matches, PCRE2 and PCRE1 differ in behavior when lookbehinds
1244 // are involved. PCRE2 reports the real begin of the match and the maximum
1245 // used lookbehind as distinct information; PCRE1 instead automatically
1246 // adjusted ovector[0] to include the maximum lookbehind.
1247 //
1248 // For instance, given the pattern "\bstring\b", and the subject "a str":
1249 // * PCRE1 reports partial, capturing " str"
1250 // * PCRE2 reports partial, capturing "str" with a lookbehind of 1
1251 //
1252 // To keep behavior, emulate PCRE1 here.
1253 // (Eventually, we could expose the lookbehind info in a future patch.)
1254 if (result == PCRE2_ERROR_PARTIAL) {
1255 unsigned int maximumLookBehind;
1256 pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_MAXLOOKBEHIND, &maximumLookBehind);
1257 capturedOffsets[0] -= maximumLookBehind;
1258 }
1259 }
1260
1261 pcre2_match_data_free_16(matchData);
1262 pcre2_match_context_free_16(matchContext);
1263}
1264
1269 const QString &subjectStorage,
1270 QStringView subject,
1272 QRegularExpression::MatchOptions matchOptions)
1273 : regularExpression(re),
1274 subjectStorage(subjectStorage),
1275 subject(subject),
1276 matchType(matchType),
1277 matchOptions(matchOptions)
1278{
1279}
1280
1285{
1288
1291 subject,
1292 matchType,
1293 matchOptions);
1294
1295 // Note the DontCheckSubjectString passed for the check of the subject string:
1296 // if we're advancing a match on the same subject,
1297 // then that subject was already checked at least once (when this object
1298 // was created, or when the object that created this one was created, etc.)
1299 regularExpression.d->doMatch(nextPrivate,
1302 this);
1303 return QRegularExpressionMatch(*nextPrivate);
1304}
1305
1311 QRegularExpression::MatchOptions matchOptions,
1313 : next(next),
1314 regularExpression(re),
1315 matchType(matchType), matchOptions(matchOptions)
1316{
1317}
1318
1326
1327// PUBLIC API
1328
1339
1348{
1349 d->pattern = pattern;
1350 d->patternOptions = options;
1351}
1352
1359
1380
1382
1383
1388
1402{
1403 return d->pattern;
1404}
1405
1413{
1414 if (d->pattern == pattern)
1415 return;
1416 d.detach();
1417 d->isDirty = true;
1418 d->pattern = pattern;
1419}
1420
1426QRegularExpression::PatternOptions QRegularExpression::patternOptions() const
1427{
1428 return d->patternOptions;
1429}
1430
1437void QRegularExpression::setPatternOptions(PatternOptions options)
1438{
1439 if (d->patternOptions == options)
1440 return;
1441 d.detach();
1442 d->isDirty = true;
1443 d->patternOptions = options;
1444}
1445
1455{
1456 if (!isValid()) // will compile the pattern
1457 return -1;
1458 return d->capturingCount;
1459}
1460
1487{
1488 if (!isValid()) // isValid() will compile the pattern
1489 return QStringList();
1490
1491 // namedCapturingTable will point to a table of
1492 // namedCapturingTableEntryCount entries, each one of which
1493 // contains one ushort followed by the name, NUL terminated.
1494 // The ushort is the numerical index of the name in the pattern.
1495 // The length of each entry is namedCapturingTableEntrySize.
1496 PCRE2_SPTR16 *namedCapturingTable;
1497 unsigned int namedCapturingTableEntryCount;
1498 unsigned int namedCapturingTableEntrySize;
1499
1500 pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
1501 pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
1502 pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
1503
1504 // The +1 is for the implicit group #0
1506
1507 for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
1508 const auto currentNamedCapturingTableRow =
1509 reinterpret_cast<const char16_t *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
1510
1511 const int index = *currentNamedCapturingTableRow;
1512 result[index] = QStringView(currentNamedCapturingTableRow + 1).toString();
1513 }
1514
1515 return result;
1516}
1517
1526{
1527 d.data()->compilePattern();
1528 return d->compiledPattern;
1529}
1530
1538{
1539 d.data()->compilePattern();
1540 if (d->errorCode) {
1542 int errorStringLength;
1543 do {
1545 errorStringLength = pcre2_get_error_message_16(d->errorCode,
1546 reinterpret_cast<ushort *>(errorString.data()),
1547 errorString.size());
1548 } while (errorStringLength < 0);
1549 errorString.resize(errorStringLength);
1550
1551#ifdef QT_NO_TRANSLATION
1552 return errorString;
1553#else
1554 return QCoreApplication::translate("QRegularExpression", std::move(errorString).toLatin1().constData());
1555#endif
1556 }
1557#ifdef QT_NO_TRANSLATION
1558 return u"no error"_s;
1559#else
1560 return QCoreApplication::translate("QRegularExpression", "no error");
1561#endif
1562}
1563
1572{
1573 d.data()->compilePattern();
1574 return d->errorOffset;
1575}
1576
1589 MatchType matchType,
1590 MatchOptions matchOptions) const
1591{
1592 d.data()->compilePattern();
1593 auto priv = new QRegularExpressionMatchPrivate(*this,
1594 subject,
1595 QStringView(subject),
1596 matchType,
1597 matchOptions);
1598 d->doMatch(priv, offset);
1600}
1601
1602#if QT_DEPRECATED_SINCE(6, 8)
1612 MatchType matchType,
1613 MatchOptions matchOptions) const
1614{
1615 return matchView(subjectView, offset, matchType, matchOptions);
1616}
1617#endif // QT_DEPRECATED_SINCE(6, 8)
1618
1637 MatchType matchType,
1638 MatchOptions matchOptions) const
1639{
1640 d.data()->compilePattern();
1641 auto priv = new QRegularExpressionMatchPrivate(*this,
1642 QString(),
1643 subjectView,
1644 matchType,
1645 matchOptions);
1646 d->doMatch(priv, offset);
1648}
1649
1663 MatchType matchType,
1664 MatchOptions matchOptions) const
1665{
1668 matchType,
1669 matchOptions,
1670 match(subject, offset, matchType, matchOptions));
1671
1673}
1674
1675#if QT_DEPRECATED_SINCE(6, 8)
1685 MatchType matchType,
1686 MatchOptions matchOptions) const
1687{
1688 return globalMatchView(subjectView, offset, matchType, matchOptions);
1689}
1690#endif // QT_DEPRECATED_SINCE(6, 8)
1691
1712 MatchType matchType,
1713 MatchOptions matchOptions) const
1714{
1717 matchType,
1718 matchOptions,
1719 matchView(subjectView, offset, matchType, matchOptions));
1720
1722}
1723
1733{
1734 d.data()->compilePattern();
1735}
1736
1747 const QRegularExpression &rhs) noexcept
1748{
1749 return (lhs.d == rhs.d) ||
1750 (lhs.d->pattern == rhs.d->pattern && lhs.d->patternOptions == rhs.d->patternOptions);
1751}
1779size_t qHash(const QRegularExpression &key, size_t seed) noexcept
1780{
1781 return qHashMulti(seed, key.d->pattern, key.d->patternOptions);
1782}
1783
1810{
1812 const qsizetype count = str.size();
1813 result.reserve(count * 2);
1814
1815 // everything but [a-zA-Z0-9_] gets escaped,
1816 // cf. perldoc -f quotemeta
1817 for (qsizetype i = 0; i < count; ++i) {
1818 const QChar current = str.at(i);
1819
1820 if (current == QChar::Null) {
1821 // unlike Perl, a literal NUL must be escaped with
1822 // "\\0" (backslash + 0) and not "\\\0" (backslash + NUL),
1823 // because pcre16_compile uses a NUL-terminated string
1824 result.append(u'\\');
1825 result.append(u'0');
1826 } else if ((current < u'a' || current > u'z') &&
1827 (current < u'A' || current > u'Z') &&
1828 (current < u'0' || current > u'9') &&
1829 current != u'_') {
1830 result.append(u'\\');
1831 result.append(current);
1832 if (current.isHighSurrogate() && i < (count - 1))
1833 result.append(str.at(++i));
1834 } else {
1835 result.append(current);
1836 }
1837 }
1838
1839 result.squeeze();
1840 return result;
1841}
1842
1932{
1933 const qsizetype wclen = pattern.size();
1934 QString rx;
1935 rx.reserve(wclen + wclen / 16);
1936 qsizetype i = 0;
1937 const QChar *wc = pattern.data();
1938
1939 struct GlobSettings {
1940 char16_t nativePathSeparator;
1941 QStringView starEscape;
1942 QStringView questionMarkEscape;
1943 };
1944
1945 const GlobSettings settings = [options]() {
1946 if (options.testFlag(NonPathWildcardConversion)) {
1947 // using [\d\D] to mean "match everything";
1948 // dot doesn't match newlines, unless in /s mode
1949 return GlobSettings{ u'\0', u"[\\d\\D]*", u"[\\d\\D]" };
1950 } else {
1951#ifdef Q_OS_WIN
1952 return GlobSettings{ u'\\', u"[^/\\\\]*", u"[^/\\\\]" };
1953#else
1954 return GlobSettings{ u'/', u"[^/]*", u"[^/]" };
1955#endif
1956 }
1957 }();
1958
1959 while (i < wclen) {
1960 const QChar c = wc[i++];
1961 switch (c.unicode()) {
1962 case '*':
1963 rx += settings.starEscape;
1964 break;
1965 case '?':
1966 rx += settings.questionMarkEscape;
1967 break;
1968 // When not using filepath globbing: \ is escaped, / is itself
1969 // When using filepath globbing:
1970 // * Unix: \ gets escaped. / is itself
1971 // * Windows: \ and / can match each other -- they become [/\\] in regexp
1972 case '\\':
1973#ifdef Q_OS_WIN
1974 if (options.testFlag(NonPathWildcardConversion))
1975 rx += u"\\\\";
1976 else
1977 rx += u"[/\\\\]";
1978 break;
1979 case '/':
1980 if (options.testFlag(NonPathWildcardConversion))
1981 rx += u'/';
1982 else
1983 rx += u"[/\\\\]";
1984 break;
1985#endif
1986 case '$':
1987 case '(':
1988 case ')':
1989 case '+':
1990 case '.':
1991 case '^':
1992 case '{':
1993 case '|':
1994 case '}':
1995 rx += u'\\';
1996 rx += c;
1997 break;
1998 case '[':
1999 rx += c;
2000 // Support for the [!abc] or [!a-c] syntax
2001 if (i < wclen) {
2002 if (wc[i] == u'!') {
2003 rx += u'^';
2004 ++i;
2005 }
2006
2007 if (i < wclen && wc[i] == u']')
2008 rx += wc[i++];
2009
2010 while (i < wclen && wc[i] != u']') {
2011 if (!options.testFlag(NonPathWildcardConversion)) {
2012 // The '/' appearing in a character class invalidates the
2013 // regular expression parsing. It also concerns '\\' on
2014 // Windows OS types.
2015 if (wc[i] == u'/' || wc[i] == settings.nativePathSeparator)
2016 return rx;
2017 }
2018 if (wc[i] == u'\\')
2019 rx += u'\\';
2020 rx += wc[i++];
2021 }
2022 }
2023 break;
2024 default:
2025 rx += c;
2026 break;
2027 }
2028 }
2029
2030 if (!(options & UnanchoredWildcardConversion))
2032
2033 return rx;
2034}
2035
2056
2070{
2071 return QString()
2072 + "\\A(?:"_L1
2073 + expression
2074 + ")\\z"_L1;
2075}
2076
2097
2104
2106
2107
2116
2140
2163 : d(&dd)
2164{
2165}
2166
2177
2178
2190
2198QRegularExpression::MatchOptions QRegularExpressionMatch::matchOptions() const
2199{
2200 return d->matchOptions;
2201}
2202
2218{
2219 return d->capturedCount - 1;
2220}
2221
2246{
2247 const int nth = d->regularExpression.d->captureIndexForName(name);
2248 return hasCaptured(nth);
2249}
2250
2274{
2275 if (nth < 0 || nth > lastCapturedIndex())
2276 return false;
2277
2278 return d->capturedOffsets.at(nth * 2) != -1;
2279}
2280
2294{
2295 return capturedView(nth).toString();
2296}
2297
2313{
2314 if (!hasCaptured(nth))
2315 return QStringView();
2316
2318
2319 if (start == -1) // didn't capture
2320 return QStringView();
2321
2322 return d->subject.mid(start, capturedLength(nth));
2323}
2324
2340{
2341 if (name.isEmpty()) {
2342 qWarning("QRegularExpressionMatch::captured: empty capturing group name passed");
2343 return QString();
2344 }
2345
2346 return capturedView(name).toString();
2347}
2348
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
2450{
2451 if (name.isEmpty()) {
2452 qWarning("QRegularExpressionMatch::capturedStart: empty capturing group name passed");
2453 return -1;
2454 }
2456 if (nth == -1)
2457 return -1;
2458 return capturedStart(nth);
2459}
2460
2476{
2477 if (name.isEmpty()) {
2478 qWarning("QRegularExpressionMatch::capturedLength: empty capturing group name passed");
2479 return 0;
2480 }
2482 if (nth == -1)
2483 return 0;
2484 return capturedLength(nth);
2485}
2486
2501{
2502 if (name.isEmpty()) {
2503 qWarning("QRegularExpressionMatch::capturedEnd: empty capturing group name passed");
2504 return -1;
2505 }
2507 if (nth == -1)
2508 return -1;
2509 return capturedEnd(nth);
2510}
2511
2519{
2520 return d->hasMatch;
2521}
2522
2534{
2535 return d->hasPartialMatch;
2536}
2537
2546{
2547 return d->isValid;
2548}
2549
2554 : d(&dd)
2555{
2556}
2557
2577
2584
2586
2587
2597
2617{
2618 d = iterator.d;
2619 return *this;
2620}
2621
2649{
2650 return d->next.isValid();
2651}
2652
2660{
2661 return d->hasNext();
2662}
2663
2671{
2672 if (!hasNext())
2673 qWarning("QRegularExpressionMatchIterator::peekNext() called on an iterator already at end");
2674
2675 return d->next;
2676}
2677
2685{
2686 if (!hasNext()) {
2687 qWarning("QRegularExpressionMatchIterator::next() called on an iterator already at end");
2688 return d.constData()->next;
2689 }
2690
2691 d.detach();
2692 return std::exchange(d->next, d->next.d.constData()->nextMatch());
2693}
2694
2705
2717
2725QRegularExpression::MatchOptions QRegularExpressionMatchIterator::matchOptions() const
2726{
2727 return d->matchOptions;
2728}
2729
2737
2743#ifndef QT_NO_DATASTREAM
2752{
2753 out << re.pattern() << quint32(re.patternOptions().toInt());
2754 return out;
2755}
2756
2765{
2767 quint32 patternOptions;
2768 in >> pattern >> patternOptions;
2769 re.setPattern(pattern);
2770 re.setPatternOptions(QRegularExpression::PatternOptions::fromInt(patternOptions));
2771 return in;
2772}
2773#endif
2774
2775#ifndef QT_NO_DEBUG_STREAM
2785{
2786 QDebugStateSaver saver(debug);
2787 debug.nospace() << "QRegularExpression(" << re.pattern() << ", " << re.patternOptions() << ')';
2788 return debug;
2789}
2790
2799QDebug operator<<(QDebug debug, QRegularExpression::PatternOptions patternOptions)
2800{
2801 QDebugStateSaver saver(debug);
2803
2804 if (patternOptions == QRegularExpression::NoPatternOption) {
2805 flags = "NoPatternOption";
2806 } else {
2807 flags.reserve(200); // worst case...
2808 if (patternOptions & QRegularExpression::CaseInsensitiveOption)
2809 flags.append("CaseInsensitiveOption|");
2811 flags.append("DotMatchesEverythingOption|");
2812 if (patternOptions & QRegularExpression::MultilineOption)
2813 flags.append("MultilineOption|");
2815 flags.append("ExtendedPatternSyntaxOption|");
2817 flags.append("InvertedGreedinessOption|");
2818 if (patternOptions & QRegularExpression::DontCaptureOption)
2819 flags.append("DontCaptureOption|");
2821 flags.append("UseUnicodePropertiesOption|");
2822 flags.chop(1);
2823 }
2824
2825 debug.nospace() << "QRegularExpression::PatternOptions(" << flags << ')';
2826
2827 return debug;
2828}
2838{
2839 QDebugStateSaver saver(debug);
2840 debug.nospace() << "QRegularExpressionMatch(";
2841
2842 if (!match.isValid()) {
2843 debug << "Invalid)";
2844 return debug;
2845 }
2846
2847 debug << "Valid";
2848
2849 if (match.hasMatch()) {
2850 debug << ", has match: ";
2851 for (int i = 0; i <= match.lastCapturedIndex(); ++i) {
2852 debug << i
2853 << ":(" << match.capturedStart(i) << ", " << match.capturedEnd(i)
2854 << ", " << match.captured(i) << ')';
2855 if (i < match.lastCapturedIndex())
2856 debug << ", ";
2857 }
2858 } else if (match.hasPartialMatch()) {
2859 debug << ", has partial match: ("
2860 << match.capturedStart(0) << ", "
2861 << match.capturedEnd(0) << ", "
2862 << match.captured(0) << ')';
2863 } else {
2864 debug << ", no match";
2865 }
2866
2867 debug << ')';
2868
2869 return debug;
2870}
2871#endif
2872
2873// fool lupdate: make it extract those strings for translation, but don't put them
2874// inside Qt -- they're already inside libpcre (cf. man 3 pcreapi, pcre_compile.c).
2875#if 0
2876
2877/* PCRE is a library of functions to support regular expressions whose syntax
2878and semantics are as close as possible to those of the Perl 5 language.
2879
2880 Written by Philip Hazel
2881 Original API code Copyright (c) 1997-2012 University of Cambridge
2882 New API code Copyright (c) 2015 University of Cambridge
2883
2884-----------------------------------------------------------------------------
2885Redistribution and use in source and binary forms, with or without
2886modification, are permitted provided that the following conditions are met:
2887
2888 * Redistributions of source code must retain the above copyright notice,
2889 this list of conditions and the following disclaimer.
2890
2891 * Redistributions in binary form must reproduce the above copyright
2892 notice, this list of conditions and the following disclaimer in the
2893 documentation and/or other materials provided with the distribution.
2894
2895 * Neither the name of the University of Cambridge nor the names of its
2896 contributors may be used to endorse or promote products derived from
2897 this software without specific prior written permission.
2898
2899THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2900AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2901IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2902ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2903LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2904CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2905SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2906INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2907CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2908ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2909POSSIBILITY OF SUCH DAMAGE.
2910-----------------------------------------------------------------------------
2911*/
2912
2913static const char *pcreCompileErrorCodes[] =
2914{
2915 QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
2916 QT_TRANSLATE_NOOP("QRegularExpression", "\\ at end of pattern"),
2917 QT_TRANSLATE_NOOP("QRegularExpression", "\\c at end of pattern"),
2918 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character follows \\"),
2919 QT_TRANSLATE_NOOP("QRegularExpression", "numbers out of order in {} quantifier"),
2920 QT_TRANSLATE_NOOP("QRegularExpression", "number too big in {} quantifier"),
2921 QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating ] for character class"),
2922 QT_TRANSLATE_NOOP("QRegularExpression", "escape sequence is invalid in character class"),
2923 QT_TRANSLATE_NOOP("QRegularExpression", "range out of order in character class"),
2924 QT_TRANSLATE_NOOP("QRegularExpression", "quantifier does not follow a repeatable item"),
2925 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unexpected repeat"),
2926 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (? or (?-"),
2927 QT_TRANSLATE_NOOP("QRegularExpression", "POSIX named classes are supported only within a class"),
2928 QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
2929 QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis"),
2930 QT_TRANSLATE_NOOP("QRegularExpression", "reference to non-existent subpattern"),
2931 QT_TRANSLATE_NOOP("QRegularExpression", "pattern passed as NULL"),
2932 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognised compile-time option bit(s)"),
2933 QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after (?# comment"),
2934 QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
2935 QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too large"),
2936 QT_TRANSLATE_NOOP("QRegularExpression", "failed to allocate heap memory"),
2937 QT_TRANSLATE_NOOP("QRegularExpression", "unmatched closing parenthesis"),
2938 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: code overflow"),
2939 QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis for condition"),
2940 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is not fixed length"),
2941 QT_TRANSLATE_NOOP("QRegularExpression", "a relative value of zero is not allowed"),
2942 QT_TRANSLATE_NOOP("QRegularExpression", "conditional subpattern contains more than two branches"),
2943 QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?( or (?(?C)"),
2944 QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+ or (?-"),
2945 QT_TRANSLATE_NOOP("QRegularExpression", "unknown POSIX class name"),
2946 QT_TRANSLATE_NOOP("QRegularExpression", "internal error in pcre2_study(): should not occur"),
2947 QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have Unicode support"),
2948 QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"),
2949 QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\x{} or \\o{} is too large"),
2950 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind is too complicated"),
2951 QT_TRANSLATE_NOOP("QRegularExpression", "\\C is not allowed in a lookbehind assertion in UTF-" "16" " mode"),
2952 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2 does not support \\F, \\L, \\l, \\N{name}, \\U, or \\u"),
2953 QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is greater than 255"),
2954 QT_TRANSLATE_NOOP("QRegularExpression", "closing parenthesis for (?C expected"),
2955 QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in (*VERB) name"),
2956 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?P"),
2957 QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in subpattern name (missing terminator?)"),
2958 QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name (PCRE2_DUPNAMES not set)"),
2959 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name must start with a non-digit"),
2960 QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have support for \\P, \\p, or \\X"),
2961 QT_TRANSLATE_NOOP("QRegularExpression", "malformed \\P or \\p sequence"),
2962 QT_TRANSLATE_NOOP("QRegularExpression", "unknown property name after \\P or \\p"),
2963 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum " "32" " code units)"),
2964 QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum " "10000" ")"),
2965 QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"),
2966 QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 in 8-bit non-UTF-8 mode"),
2967 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: overran compiling workspace"),
2968 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: previously-checked referenced subpattern not found"),
2969 QT_TRANSLATE_NOOP("QRegularExpression", "DEFINE subpattern contains more than one branch"),
2970 QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"),
2971 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown newline setting"),
2972 QT_TRANSLATE_NOOP("QRegularExpression", "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number"),
2973 QT_TRANSLATE_NOOP("QRegularExpression", "(?R (recursive pattern call) must be followed by a closing parenthesis"),
2974 QT_TRANSLATE_NOOP("QRegularExpression", "obsolete error (should not occur)"),
2975 QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized or malformed"),
2976 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern number is too big"),
2977 QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name expected"),
2978 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: parsed pattern overflow"),
2979 QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"),
2980 QT_TRANSLATE_NOOP("QRegularExpression", "different names for subpatterns of the same number are not allowed"),
2981 QT_TRANSLATE_NOOP("QRegularExpression", "(*MARK) must have an argument"),
2982 QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
2983 QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a printable ASCII character"),
2984 QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a letter or one of [\\]^_?"),
2985 QT_TRANSLATE_NOOP("QRegularExpression", "\\k is not followed by a braced, angle-bracketed, or quoted name"),
2986 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown meta code in check_lookbehinds()"),
2987 QT_TRANSLATE_NOOP("QRegularExpression", "\\N is not supported in a class"),
2988 QT_TRANSLATE_NOOP("QRegularExpression", "callout string is too long"),
2989 QT_TRANSLATE_NOOP("QRegularExpression", "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)"),
2990 QT_TRANSLATE_NOOP("QRegularExpression", "using UTF is disabled by the application"),
2991 QT_TRANSLATE_NOOP("QRegularExpression", "using UCP is disabled by the application"),
2992 QT_TRANSLATE_NOOP("QRegularExpression", "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)"),
2993 QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\u.... sequence is too large"),
2994 QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{} or \\N{U+}"),
2995 QT_TRANSLATE_NOOP("QRegularExpression", "syntax error or number too big in (?(VERSION condition"),
2996 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in auto_possessify()"),
2997 QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating delimiter for callout with string argument"),
2998 QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized string delimiter follows (?C"),
2999 QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled by the application"),
3000 QT_TRANSLATE_NOOP("QRegularExpression", "(?| and/or (?J: or (?x: parentheses are too deeply nested"),
3001 QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled in this PCRE2 library"),
3002 QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too complicated"),
3003 QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is too long"),
3004 QT_TRANSLATE_NOOP("QRegularExpression", "pattern string is longer than the limit set by the application"),
3005 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown code in parsed pattern"),
3006 QT_TRANSLATE_NOOP("QRegularExpression", "internal error: bad code value in parsed_skip()"),
3007 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode"),
3008 QT_TRANSLATE_NOOP("QRegularExpression", "invalid option bits with PCRE2_LITERAL"),
3009 QT_TRANSLATE_NOOP("QRegularExpression", "\\N{U+dddd} is supported only in Unicode (UTF) mode"),
3010 QT_TRANSLATE_NOOP("QRegularExpression", "invalid hyphen in option setting"),
3011 QT_TRANSLATE_NOOP("QRegularExpression", "(*alpha_assertion) not recognized"),
3012 QT_TRANSLATE_NOOP("QRegularExpression", "script runs require Unicode support, which this version of PCRE2 does not have"),
3013 QT_TRANSLATE_NOOP("QRegularExpression", "too many capturing groups (maximum 65535)"),
3014 QT_TRANSLATE_NOOP("QRegularExpression", "atomic assertion expected after (?( or (?(?C)"),
3015 QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
3016 QT_TRANSLATE_NOOP("QRegularExpression", "no match"),
3017 QT_TRANSLATE_NOOP("QRegularExpression", "partial match"),
3018 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 1 byte missing at end"),
3019 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 2 bytes missing at end"),
3020 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 3 bytes missing at end"),
3021 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 4 bytes missing at end"),
3022 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5 bytes missing at end"),
3023 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 2 top bits not 0x80"),
3024 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 3 top bits not 0x80"),
3025 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 4 top bits not 0x80"),
3026 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 5 top bits not 0x80"),
3027 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 6 top bits not 0x80"),
3028 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5-byte character is not allowed (RFC 3629)"),
3029 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 6-byte character is not allowed (RFC 3629)"),
3030 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points greater than 0x10ffff are not defined"),
3031 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points 0xd800-0xdfff are not defined"),
3032 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 2-byte sequence"),
3033 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 3-byte sequence"),
3034 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 4-byte sequence"),
3035 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 5-byte sequence"),
3036 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 6-byte sequence"),
3037 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: isolated byte with 0x80 bit set"),
3038 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: illegal byte (0xfe or 0xff)"),
3039 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: missing low surrogate at end"),
3040 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: invalid low surrogate"),
3041 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: isolated low surrogate"),
3042 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points 0xd800-0xdfff are not defined"),
3043 QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points greater than 0x10ffff are not defined"),
3044 QT_TRANSLATE_NOOP("QRegularExpression", "bad data value"),
3045 QT_TRANSLATE_NOOP("QRegularExpression", "patterns do not all use the same character tables"),
3046 QT_TRANSLATE_NOOP("QRegularExpression", "magic number missing"),
3047 QT_TRANSLATE_NOOP("QRegularExpression", "pattern compiled in wrong mode: 8/16/32-bit error"),
3048 QT_TRANSLATE_NOOP("QRegularExpression", "bad offset value"),
3049 QT_TRANSLATE_NOOP("QRegularExpression", "bad option value"),
3050 QT_TRANSLATE_NOOP("QRegularExpression", "invalid replacement string"),
3051 QT_TRANSLATE_NOOP("QRegularExpression", "bad offset into UTF string"),
3052 QT_TRANSLATE_NOOP("QRegularExpression", "callout error code"),
3053 QT_TRANSLATE_NOOP("QRegularExpression", "invalid data in workspace for DFA restart"),
3054 QT_TRANSLATE_NOOP("QRegularExpression", "too much recursion for DFA matching"),
3055 QT_TRANSLATE_NOOP("QRegularExpression", "backreference condition or recursion test is not supported for DFA matching"),
3056 QT_TRANSLATE_NOOP("QRegularExpression", "function is not supported for DFA matching"),
3057 QT_TRANSLATE_NOOP("QRegularExpression", "pattern contains an item that is not supported for DFA matching"),
3058 QT_TRANSLATE_NOOP("QRegularExpression", "workspace size exceeded in DFA matching"),
3059 QT_TRANSLATE_NOOP("QRegularExpression", "internal error - pattern overwritten?"),
3060 QT_TRANSLATE_NOOP("QRegularExpression", "bad JIT option"),
3061 QT_TRANSLATE_NOOP("QRegularExpression", "JIT stack limit reached"),
3062 QT_TRANSLATE_NOOP("QRegularExpression", "match limit exceeded"),
3063 QT_TRANSLATE_NOOP("QRegularExpression", "no more memory"),
3064 QT_TRANSLATE_NOOP("QRegularExpression", "unknown substring"),
3065 QT_TRANSLATE_NOOP("QRegularExpression", "non-unique substring name"),
3066 QT_TRANSLATE_NOOP("QRegularExpression", "NULL argument passed"),
3067 QT_TRANSLATE_NOOP("QRegularExpression", "nested recursion at the same subject position"),
3068 QT_TRANSLATE_NOOP("QRegularExpression", "matching depth limit exceeded"),
3069 QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not available"),
3070 QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not set"),
3071 QT_TRANSLATE_NOOP("QRegularExpression", "offset limit set without PCRE2_USE_OFFSET_LIMIT"),
3072 QT_TRANSLATE_NOOP("QRegularExpression", "bad escape sequence in replacement string"),
3073 QT_TRANSLATE_NOOP("QRegularExpression", "expected closing curly bracket in replacement string"),
3074 QT_TRANSLATE_NOOP("QRegularExpression", "bad substitution in replacement string"),
3075 QT_TRANSLATE_NOOP("QRegularExpression", "match with end before start or start moved backwards is not supported"),
3076 QT_TRANSLATE_NOOP("QRegularExpression", "too many replacements (more than INT_MAX)"),
3077 QT_TRANSLATE_NOOP("QRegularExpression", "bad serialized data"),
3078 QT_TRANSLATE_NOOP("QRegularExpression", "heap limit exceeded"),
3079 QT_TRANSLATE_NOOP("QRegularExpression", "invalid syntax"),
3080 QT_TRANSLATE_NOOP("QRegularExpression", "internal error - duplicate substitution match"),
3081 QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching"),
3082 QT_TRANSLATE_NOOP("QRegularExpression", "INTERNAL ERROR: invalid substring offset")
3083};
3084#endif // #if 0
3085
\inmodule QtCore
\inmodule QtCore
Definition qbytearray.h:57
void reserve(qsizetype size)
Attempts to allocate memory for at least size bytes.
Definition qbytearray.h:634
\inmodule QtCore
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore\reentrant
Definition qdatastream.h:46
\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.
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
\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 hasCaptured(QAnyStringView name) const
bool hasPartialMatch() const
Returns true if the regular expression partially matched against the subject string,...
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
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:78
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1121
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:129
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1240
void resize(qsizetype size)
Sets the size of the string to size characters.
Definition qstring.cpp:2668
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
QList< QString > QStringList
Constructs a string list that contains the given string, str.
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:164
#define qWarning
Definition qlogging.h:166
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 *)
bool comparesEqual(const QRegularExpression &lhs, const QRegularExpression &rhs) noexcept
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:1543
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:50
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned short ushort
Definition qtypes.h:33
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(QAnyStringView name) const
void doMatch(QRegularExpressionMatchPrivate *priv, qsizetype offset, CheckSubjectStringOption checkSubjectStringOption=CheckSubjectString, const QRegularExpressionMatchPrivate *previous=nullptr) const
QRegularExpression::PatternOptions patternOptions