QtBase  v6.3.1
qregularexpression.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 Giuseppe D'Angelo <dangelog@gmail.com>.
4 ** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
5 ** Copyright (C) 2021 The Qt Company Ltd.
6 ** Contact: https://www.qt.io/licensing/
7 **
8 ** This file is part of the QtCore module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Commercial License Usage
12 ** Licensees holding valid commercial Qt licenses may use this file in
13 ** accordance with the commercial license agreement provided with the
14 ** Software or, alternatively, in accordance with the terms contained in
15 ** a written agreement between you and The Qt Company. For licensing terms
16 ** and conditions see https://www.qt.io/terms-conditions. For further
17 ** information use the contact form at https://www.qt.io/contact-us.
18 **
19 ** GNU Lesser General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU Lesser
21 ** General Public License version 3 as published by the Free Software
22 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
23 ** packaging of this file. Please review the following information to
24 ** ensure the GNU Lesser General Public License version 3 requirements
25 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26 **
27 ** GNU General Public License Usage
28 ** Alternatively, this file may be used under the terms of the GNU
29 ** General Public License version 2.0 or (at your option) the GNU General
30 ** Public license version 3 or any later version approved by the KDE Free
31 ** Qt Foundation. The licenses are as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33 ** included in the packaging of this file. Please review the following
34 ** information to ensure the GNU General Public License requirements will
35 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36 ** https://www.gnu.org/licenses/gpl-3.0.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qregularexpression.h"
43 
44 #include <QtCore/qcoreapplication.h>
45 #include <QtCore/qhashfunctions.h>
46 #include <QtCore/qlist.h>
47 #include <QtCore/qmutex.h>
48 #include <QtCore/qstringlist.h>
49 #include <QtCore/qdebug.h>
50 #include <QtCore/qthreadstorage.h>
51 #include <QtCore/qglobal.h>
52 #include <QtCore/qatomic.h>
53 #include <QtCore/qdatastream.h>
54 
55 #if defined(Q_OS_MACOS)
56 #include <QtCore/private/qcore_mac_p.h>
57 #endif
58 
59 #define PCRE2_CODE_UNIT_WIDTH 16
60 
61 #include <pcre2.h>
62 
64 
701 static int convertToPcreOptions(QRegularExpression::PatternOptions patternOptions)
702 {
703  int options = 0;
704 
705  if (patternOptions & QRegularExpression::CaseInsensitiveOption)
706  options |= PCRE2_CASELESS;
708  options |= PCRE2_DOTALL;
709  if (patternOptions & QRegularExpression::MultilineOption)
710  options |= PCRE2_MULTILINE;
712  options |= PCRE2_EXTENDED;
714  options |= PCRE2_UNGREEDY;
715  if (patternOptions & QRegularExpression::DontCaptureOption)
716  options |= PCRE2_NO_AUTO_CAPTURE;
718  options |= PCRE2_UCP;
719 
720  return options;
721 }
722 
726 static int convertToPcreOptions(QRegularExpression::MatchOptions matchOptions)
727 {
728  int options = 0;
729 
731  options |= PCRE2_ANCHORED;
733  options |= PCRE2_NO_UTF_CHECK;
734 
735  return options;
736 }
737 
739 {
743 
744  void cleanCompiledPattern();
745  void compilePattern();
746  void getPatternInfo();
747  void optimizePattern();
748 
752  };
753 
756  CheckSubjectStringOption checkSubjectStringOption = CheckSubjectString,
757  const QRegularExpressionMatchPrivate *previous = nullptr) const;
758 
760 
761  // sizeof(QSharedData) == 4, so start our members with an enum
762  QRegularExpression::PatternOptions patternOptions;
764 
765  // *All* of the following members are managed while holding this mutex,
766  // except for isDirty which is set to true by QRegularExpression setters
767  // (right after a detach happened).
768  mutable QMutex mutex;
769 
770  // The PCRE code pointer is reference-counted by the QRegularExpressionPrivate
771  // objects themselves; when the private is copied (i.e. a detach happened)
772  // it is set to nullptr
773  pcre2_code_16 *compiledPattern;
778  bool isDirty;
779 };
780 
782 {
784  const QString &subjectStorage,
787  QRegularExpression::MatchOptions matchOptions);
788 
790 
792 
793  // subject is what we match upon. If we've been asked to match over
794  // a QString, then subjectStorage is a copy of that string
795  // (so that it's kept alive by us)
798 
800  const QRegularExpression::MatchOptions matchOptions;
801 
802  // the capturedOffsets vector contains pairs of (start, end) positions
803  // for each captured substring
805 
806  int capturedCount = 0;
807 
808  bool hasMatch = false;
809  bool hasPartialMatch = false;
810  bool isValid = false;
811 };
812 
814 {
817  QRegularExpression::MatchOptions matchOptions,
819 
820  bool hasNext() const;
824  const QRegularExpression::MatchOptions matchOptions;
825 };
826 
831  : d(&dd)
832 {
833 }
834 
839  : QSharedData(),
840  patternOptions(),
841  pattern(),
842  mutex(),
843  compiledPattern(nullptr),
844  errorCode(0),
845  errorOffset(-1),
846  capturingCount(0),
847  usingCrLfNewlines(false),
848  isDirty(true)
849 {
850 }
851 
856 {
858 }
859 
870  : QSharedData(other),
871  patternOptions(other.patternOptions),
873  mutex(),
874  compiledPattern(nullptr),
875  errorCode(0),
876  errorOffset(-1),
877  capturingCount(0),
878  usingCrLfNewlines(false),
879  isDirty(true)
880 {
881 }
882 
887 {
888  pcre2_code_free_16(compiledPattern);
889  compiledPattern = nullptr;
890  errorCode = 0;
891  errorOffset = -1;
892  capturingCount = 0;
893  usingCrLfNewlines = false;
894 }
895 
900 {
901  const QMutexLocker lock(&mutex);
902 
903  if (!isDirty)
904  return;
905 
906  isDirty = false;
908 
909  int options = convertToPcreOptions(patternOptions);
910  options |= PCRE2_UTF;
911 
912  PCRE2_SIZE patternErrorOffset;
913  compiledPattern = pcre2_compile_16(reinterpret_cast<PCRE2_SPTR16>(pattern.constData()),
914  pattern.length(),
915  options,
916  &errorCode,
917  &patternErrorOffset,
918  nullptr);
919 
920  if (!compiledPattern) {
921  errorOffset = qsizetype(patternErrorOffset);
922  return;
923  } else {
924  // ignore whatever PCRE2 wrote into errorCode -- leave it to 0 to mean "no error"
925  errorCode = 0;
926  }
927 
928  optimizePattern();
929  getPatternInfo();
930 }
931 
936 {
938 
939  pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_CAPTURECOUNT, &capturingCount);
940 
941  // detect the settings for the newline
942  unsigned int patternNewlineSetting;
943  if (pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NEWLINE, &patternNewlineSetting) != 0) {
944  // no option was specified in the regexp, grab PCRE build defaults
945  pcre2_config_16(PCRE2_CONFIG_NEWLINE, &patternNewlineSetting);
946  }
947 
948  usingCrLfNewlines = (patternNewlineSetting == PCRE2_NEWLINE_CRLF) ||
949  (patternNewlineSetting == PCRE2_NEWLINE_ANY) ||
950  (patternNewlineSetting == PCRE2_NEWLINE_ANYCRLF);
951 
952  unsigned int hasJOptionChanged;
953  pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_JCHANGED, &hasJOptionChanged);
954  if (Q_UNLIKELY(hasJOptionChanged)) {
955  qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%ls'\n is using the (?J) option; duplicate capturing group names are not supported by Qt",
956  qUtf16Printable(pattern));
957  }
958 }
959 
960 
961 /*
962  Simple "smartpointer" wrapper around a pcre2_jit_stack_16, to be used with
963  QThreadStorage.
964 */
966 {
968 
969 public:
974  {
975  // The default JIT stack size in PCRE is 32K,
976  // we allocate from 32K up to 512K.
977  stack = pcre2_jit_stack_create_16(32 * 1024, 512 * 1024, nullptr);
978  }
983  {
984  if (stack)
985  pcre2_jit_stack_free_16(stack);
986  }
987 
988  pcre2_jit_stack_16 *stack;
989 };
990 
992 
993 
996 static pcre2_jit_stack_16 *qtPcreCallback(void *)
997 {
998  if (jitStacks()->hasLocalData())
999  return jitStacks()->localData()->stack;
1000 
1001  return nullptr;
1002 }
1003 
1007 static bool isJitEnabled()
1008 {
1009  QByteArray jitEnvironment = qgetenv("QT_ENABLE_REGEXP_JIT");
1010  if (!jitEnvironment.isEmpty()) {
1011  bool ok;
1012  int enableJit = jitEnvironment.toInt(&ok);
1013  return ok ? (enableJit != 0) : true;
1014  }
1015 
1016 #ifdef QT_DEBUG
1017  return false;
1018 #elif defined(Q_OS_MACOS)
1019  return !qt_mac_runningUnderRosetta();
1020 #else
1021  return true;
1022 #endif
1023 }
1024 
1035 {
1037 
1038  static const bool enableJit = isJitEnabled();
1039 
1040  if (!enableJit)
1041  return;
1042 
1044 }
1045 
1053 {
1054  Q_ASSERT(!name.isEmpty());
1055 
1056  if (!compiledPattern)
1057  return -1;
1058 
1059  // See the other usages of pcre2_pattern_info_16 for more details about this
1060  PCRE2_SPTR16 *namedCapturingTable;
1061  unsigned int namedCapturingTableEntryCount;
1062  unsigned int namedCapturingTableEntrySize;
1063 
1064  pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
1065  pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
1066  pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
1067 
1068  for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
1069  const auto currentNamedCapturingTableRow =
1070  reinterpret_cast<const char16_t *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
1071 
1072  if (name == (currentNamedCapturingTableRow + 1)) {
1073  const int index = *currentNamedCapturingTableRow;
1074  return index;
1075  }
1076  }
1077 
1078  return -1;
1079 }
1080 
1088 static int safe_pcre2_match_16(const pcre2_code_16 *code,
1089  PCRE2_SPTR16 subject, qsizetype length,
1090  qsizetype startOffset, int options,
1091  pcre2_match_data_16 *matchData,
1092  pcre2_match_context_16 *matchContext)
1093 {
1094  int result = pcre2_match_16(code, subject, length,
1095  startOffset, options, matchData, matchContext);
1096 
1097  if (result == PCRE2_ERROR_JIT_STACKLIMIT && !jitStacks()->hasLocalData()) {
1099  jitStacks()->setLocalData(p);
1100 
1101  result = pcre2_match_16(code, subject, length,
1102  startOffset, options, matchData, matchContext);
1103  }
1104 
1105  return result;
1106 }
1107 
1137  qsizetype offset,
1138  CheckSubjectStringOption checkSubjectStringOption,
1139  const QRegularExpressionMatchPrivate *previous) const
1140 {
1141  Q_ASSERT(priv);
1142  Q_ASSUME(priv != previous);
1143 
1144  const qsizetype subjectLength = priv->subject.size();
1145 
1146  if (offset < 0)
1147  offset += subjectLength;
1148 
1149  if (offset < 0 || offset > subjectLength)
1150  return;
1151 
1152  if (Q_UNLIKELY(!compiledPattern)) {
1153  qWarning("QRegularExpressionPrivate::doMatch(): called on an invalid QRegularExpression object");
1154  return;
1155  }
1156 
1157  // skip doing the actual matching if NoMatch type was requested
1158  if (priv->matchType == QRegularExpression::NoMatch) {
1159  priv->isValid = true;
1160  return;
1161  }
1162 
1163  int pcreOptions = convertToPcreOptions(priv->matchOptions);
1164 
1166  pcreOptions |= PCRE2_PARTIAL_SOFT;
1168  pcreOptions |= PCRE2_PARTIAL_HARD;
1169 
1170  if (checkSubjectStringOption == DontCheckSubjectString)
1171  pcreOptions |= PCRE2_NO_UTF_CHECK;
1172 
1173  bool previousMatchWasEmpty = false;
1174  if (previous && previous->hasMatch &&
1175  (previous->capturedOffsets.at(0) == previous->capturedOffsets.at(1))) {
1176  previousMatchWasEmpty = true;
1177  }
1178 
1179  pcre2_match_context_16 *matchContext = pcre2_match_context_create_16(nullptr);
1180  pcre2_jit_stack_assign_16(matchContext, &qtPcreCallback, nullptr);
1181  pcre2_match_data_16 *matchData = pcre2_match_data_create_from_pattern_16(compiledPattern, nullptr);
1182 
1183  // PCRE does not accept a null pointer as subject string, even if
1184  // its length is zero. We however allow it in input: a QStringView
1185  // subject may have data == nullptr. In this case, to keep PCRE
1186  // happy, pass a pointer to a dummy character.
1187  const char16_t dummySubject = 0;
1188  const char16_t * const subjectUtf16 = [&]()
1189  {
1190  const auto subjectUtf16 = priv->subject.utf16();
1191  if (subjectUtf16)
1192  return subjectUtf16;
1193  Q_ASSERT(subjectLength == 0);
1194  return &dummySubject;
1195  }();
1196 
1197  int result;
1198 
1199  if (!previousMatchWasEmpty) {
1200  result = safe_pcre2_match_16(compiledPattern,
1201  reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), subjectLength,
1202  offset, pcreOptions,
1203  matchData, matchContext);
1204  } else {
1205  result = safe_pcre2_match_16(compiledPattern,
1206  reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), subjectLength,
1207  offset, pcreOptions | PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED,
1208  matchData, matchContext);
1209 
1210  if (result == PCRE2_ERROR_NOMATCH) {
1211  ++offset;
1212 
1213  if (usingCrLfNewlines
1214  && offset < subjectLength
1215  && subjectUtf16[offset - 1] == QLatin1Char('\r')
1216  && subjectUtf16[offset] == QLatin1Char('\n')) {
1217  ++offset;
1218  } else if (offset < subjectLength
1219  && QChar::isLowSurrogate(subjectUtf16[offset])) {
1220  ++offset;
1221  }
1222 
1223  result = safe_pcre2_match_16(compiledPattern,
1224  reinterpret_cast<PCRE2_SPTR16>(subjectUtf16), subjectLength,
1225  offset, pcreOptions,
1226  matchData, matchContext);
1227  }
1228  }
1229 
1230 #ifdef QREGULAREXPRESSION_DEBUG
1231  qDebug() << "Matching" << pattern << "against" << subject
1232  << "offset" << offset
1233  << priv->matchType << priv->matchOptions << previousMatchWasEmpty
1234  << "result" << result;
1235 #endif
1236 
1237  // result == 0 means not enough space in captureOffsets; should never happen
1238  Q_ASSERT(result != 0);
1239 
1240  if (result > 0) {
1241  // full match
1242  priv->isValid = true;
1243  priv->hasMatch = true;
1244  priv->capturedCount = result;
1245  priv->capturedOffsets.resize(result * 2);
1246  } else {
1247  // no match, partial match or error
1250 
1251  if (result == PCRE2_ERROR_PARTIAL) {
1252  // partial match:
1253  // leave the start and end capture offsets (i.e. cap(0))
1254  priv->capturedCount = 1;
1255  priv->capturedOffsets.resize(2);
1256  } else {
1257  // no match or error
1258  priv->capturedCount = 0;
1259  priv->capturedOffsets.clear();
1260  }
1261  }
1262 
1263  // copy the captured substrings offsets, if any
1264  if (priv->capturedCount) {
1265  PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_16(matchData);
1266  qsizetype *const capturedOffsets = priv->capturedOffsets.data();
1267 
1268  // We rely on the fact that capturing groups that did not
1269  // capture anything have offset -1, but PCRE technically
1270  // returns "PCRE2_UNSET". Test that out, better safe than
1271  // sorry...
1272  static_assert(qsizetype(PCRE2_UNSET) == qsizetype(-1), "Internal error: PCRE2 changed its API");
1273 
1274  for (int i = 0; i < priv->capturedCount * 2; ++i)
1275  capturedOffsets[i] = qsizetype(ovector[i]);
1276 
1277  // For partial matches, PCRE2 and PCRE1 differ in behavior when lookbehinds
1278  // are involved. PCRE2 reports the real begin of the match and the maximum
1279  // used lookbehind as distinct information; PCRE1 instead automatically
1280  // adjusted ovector[0] to include the maximum lookbehind.
1281  //
1282  // For instance, given the pattern "\bstring\b", and the subject "a str":
1283  // * PCRE1 reports partial, capturing " str"
1284  // * PCRE2 reports partial, capturing "str" with a lookbehind of 1
1285  //
1286  // To keep behavior, emulate PCRE1 here.
1287  // (Eventually, we could expose the lookbehind info in a future patch.)
1288  if (result == PCRE2_ERROR_PARTIAL) {
1289  unsigned int maximumLookBehind;
1290  pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_MAXLOOKBEHIND, &maximumLookBehind);
1291  capturedOffsets[0] -= maximumLookBehind;
1292  }
1293  }
1294 
1295  pcre2_match_data_free_16(matchData);
1296  pcre2_match_context_free_16(matchContext);
1297 }
1298 
1303  const QString &subjectStorage,
1304  QStringView subject,
1306  QRegularExpression::MatchOptions matchOptions)
1307  : regularExpression(re),
1308  subjectStorage(subjectStorage),
1309  subject(subject),
1310  matchType(matchType),
1311  matchOptions(matchOptions)
1312 {
1313 }
1314 
1319 {
1320  Q_ASSERT(isValid);
1322 
1323  auto nextPrivate = new QRegularExpressionMatchPrivate(regularExpression,
1325  subject,
1326  matchType,
1327  matchOptions);
1328 
1329  // Note the DontCheckSubjectString passed for the check of the subject string:
1330  // if we're advancing a match on the same subject,
1331  // then that subject was already checked at least once (when this object
1332  // was created, or when the object that created this one was created, etc.)
1333  regularExpression.d->doMatch(nextPrivate,
1334  capturedOffsets.at(1),
1336  this);
1337  return QRegularExpressionMatch(*nextPrivate);
1338 }
1339 
1345  QRegularExpression::MatchOptions matchOptions,
1347  : next(next),
1348  regularExpression(re),
1349  matchType(matchType), matchOptions(matchOptions)
1350 {
1351 }
1352 
1357 {
1358  return next.isValid() && (next.hasMatch() || next.hasPartialMatch());
1359 }
1360 
1361 // PUBLIC API
1362 
1371 {
1372 }
1373 
1382 {
1383  d->pattern = pattern;
1384  d->patternOptions = options;
1385 }
1386 
1393  : d(re.d)
1394 {
1395 }
1396 
1415 {
1416 }
1417 
1419 
1420 
1425 {
1426  d = re.d;
1427  return *this;
1428 }
1429 
1443 {
1444  return d->pattern;
1445 }
1446 
1454 {
1455  if (d->pattern == pattern)
1456  return;
1457  d.detach();
1458  d->isDirty = true;
1459  d->pattern = pattern;
1460 }
1461 
1467 QRegularExpression::PatternOptions QRegularExpression::patternOptions() const
1468 {
1469  return d->patternOptions;
1470 }
1471 
1478 void QRegularExpression::setPatternOptions(PatternOptions options)
1479 {
1480  if (d->patternOptions == options)
1481  return;
1482  d.detach();
1483  d->isDirty = true;
1484  d->patternOptions = options;
1485 }
1486 
1496 {
1497  if (!isValid()) // will compile the pattern
1498  return -1;
1499  return d->capturingCount;
1500 }
1501 
1528 {
1529  if (!isValid()) // isValid() will compile the pattern
1530  return QStringList();
1531 
1532  // namedCapturingTable will point to a table of
1533  // namedCapturingTableEntryCount entries, each one of which
1534  // contains one ushort followed by the name, NUL terminated.
1535  // The ushort is the numerical index of the name in the pattern.
1536  // The length of each entry is namedCapturingTableEntrySize.
1537  PCRE2_SPTR16 *namedCapturingTable;
1538  unsigned int namedCapturingTableEntryCount;
1539  unsigned int namedCapturingTableEntrySize;
1540 
1541  pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
1542  pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
1543  pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
1544 
1545  // The +1 is for the implicit group #0
1547 
1548  for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
1549  const auto currentNamedCapturingTableRow =
1550  reinterpret_cast<const char16_t *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
1551 
1552  const int index = *currentNamedCapturingTableRow;
1553  result[index] = QString::fromUtf16(currentNamedCapturingTableRow + 1);
1554  }
1555 
1556  return result;
1557 }
1558 
1567 {
1568  d.data()->compilePattern();
1569  return d->compiledPattern;
1570 }
1571 
1579 {
1580  d.data()->compilePattern();
1581  if (d->errorCode) {
1583  int errorStringLength;
1584  do {
1586  errorStringLength = pcre2_get_error_message_16(d->errorCode,
1587  reinterpret_cast<ushort *>(errorString.data()),
1588  errorString.length());
1589  } while (errorStringLength < 0);
1590  errorString.resize(errorStringLength);
1591 
1592 #ifdef QT_NO_TRANSLATION
1593  return errorString;
1594 #else
1595  return QCoreApplication::translate("QRegularExpression", std::move(errorString).toLatin1().constData());
1596 #endif
1597  }
1598 #ifdef QT_NO_TRANSLATION
1599  return QLatin1String("no error");
1600 #else
1601  return QCoreApplication::translate("QRegularExpression", "no error");
1602 #endif
1603 }
1604 
1613 {
1614  d.data()->compilePattern();
1615  return d->errorOffset;
1616 }
1617 
1634  qsizetype offset,
1635  MatchType matchType,
1636  MatchOptions matchOptions) const
1637 {
1638  d.data()->compilePattern();
1639  auto priv = new QRegularExpressionMatchPrivate(*this,
1640  subject,
1641  QStringView(subject),
1642  matchType,
1643  matchOptions);
1644  d->doMatch(priv, offset);
1645  return QRegularExpressionMatch(*priv);
1646 }
1647 
1665  qsizetype offset,
1666  MatchType matchType,
1667  MatchOptions matchOptions) const
1668 {
1669  d.data()->compilePattern();
1670  auto priv = new QRegularExpressionMatchPrivate(*this,
1671  QString(),
1672  subjectView,
1673  matchType,
1674  matchOptions);
1675  d->doMatch(priv, offset);
1676  return QRegularExpressionMatch(*priv);
1677 }
1678 
1696  qsizetype offset,
1697  MatchType matchType,
1698  MatchOptions matchOptions) const
1699 {
1702  matchType,
1703  matchOptions,
1704  match(subject, offset, matchType, matchOptions));
1705 
1706  return QRegularExpressionMatchIterator(*priv);
1707 }
1708 
1728  qsizetype offset,
1729  MatchType matchType,
1730  MatchOptions matchOptions) const
1731 {
1734  matchType,
1735  matchOptions,
1736  match(subjectView, offset, matchType, matchOptions));
1737 
1738  return QRegularExpressionMatchIterator(*priv);
1739 }
1740 
1750 {
1751  d.data()->compilePattern();
1752 }
1753 
1762 {
1763  return (d == re.d) ||
1764  (d->pattern == re.d->pattern && d->patternOptions == re.d->patternOptions);
1765 }
1766 
1794 size_t qHash(const QRegularExpression &key, size_t seed) noexcept
1795 {
1796  return qHashMulti(seed, key.d->pattern, key.d->patternOptions);
1797 }
1798 
1825 {
1826  QString result;
1827  const qsizetype count = str.size();
1828  result.reserve(count * 2);
1829 
1830  // everything but [a-zA-Z0-9_] gets escaped,
1831  // cf. perldoc -f quotemeta
1832  for (qsizetype i = 0; i < count; ++i) {
1833  const QChar current = str.at(i);
1834 
1835  if (current == QChar::Null) {
1836  // unlike Perl, a literal NUL must be escaped with
1837  // "\\0" (backslash + 0) and not "\\\0" (backslash + NUL),
1838  // because pcre16_compile uses a NUL-terminated string
1839  result.append(QLatin1Char('\\'));
1840  result.append(QLatin1Char('0'));
1841  } else if ( (current < QLatin1Char('a') || current > QLatin1Char('z')) &&
1842  (current < QLatin1Char('A') || current > QLatin1Char('Z')) &&
1843  (current < QLatin1Char('0') || current > QLatin1Char('9')) &&
1844  current != QLatin1Char('_') )
1845  {
1846  result.append(QLatin1Char('\\'));
1847  result.append(current);
1848  if (current.isHighSurrogate() && i < (count - 1))
1849  result.append(str.at(++i));
1850  } else {
1851  result.append(current);
1852  }
1853  }
1854 
1855  result.squeeze();
1856  return result;
1857 }
1858 
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 #ifdef Q_OS_WIN
1940  const QLatin1Char nativePathSeparator('\\');
1941  const QLatin1String starEscape("[^/\\\\]*");
1942  const QLatin1String questionMarkEscape("[^/\\\\]");
1943 #else
1944  const QLatin1Char nativePathSeparator('/');
1945  const QLatin1String starEscape("[^/]*");
1946  const QLatin1String questionMarkEscape("[^/]");
1947 #endif
1948 
1949  while (i < wclen) {
1950  const QChar c = wc[i++];
1951  switch (c.unicode()) {
1952  case '*':
1953  rx += starEscape;
1954  break;
1955  case '?':
1956  rx += questionMarkEscape;
1957  break;
1958  case '\\':
1959 #ifdef Q_OS_WIN
1960  case '/':
1961  rx += QLatin1String("[/\\\\]");
1962  break;
1963 #endif
1964  case '$':
1965  case '(':
1966  case ')':
1967  case '+':
1968  case '.':
1969  case '^':
1970  case '{':
1971  case '|':
1972  case '}':
1973  rx += QLatin1Char('\\');
1974  rx += c;
1975  break;
1976  case '[':
1977  rx += c;
1978  // Support for the [!abc] or [!a-c] syntax
1979  if (i < wclen) {
1980  if (wc[i] == QLatin1Char('!')) {
1981  rx += QLatin1Char('^');
1982  ++i;
1983  }
1984 
1985  if (i < wclen && wc[i] == QLatin1Char(']'))
1986  rx += wc[i++];
1987 
1988  while (i < wclen && wc[i] != QLatin1Char(']')) {
1989  // The '/' appearing in a character class invalidates the
1990  // regular expression parsing. It also concerns '\\' on
1991  // Windows OS types.
1992  if (wc[i] == QLatin1Char('/') || wc[i] == nativePathSeparator)
1993  return rx;
1994  if (wc[i] == QLatin1Char('\\'))
1995  rx += QLatin1Char('\\');
1996  rx += wc[i++];
1997  }
1998  }
1999  break;
2000  default:
2001  rx += c;
2002  break;
2003  }
2004  }
2005 
2006  if (!(options & UnanchoredWildcardConversion))
2007  rx = anchoredPattern(rx);
2008 
2009  return rx;
2010 }
2011 
2026  WildcardConversionOptions options)
2027 {
2028  auto reOptions = cs == Qt::CaseSensitive ? QRegularExpression::NoPatternOption :
2030  return QRegularExpression(wildcardToRegularExpression(pattern, options), reOptions);
2031 }
2032 
2046 {
2047  return QString()
2048  + QLatin1String("\\A(?:")
2049  + expression
2050  + QLatin1String(")\\z");
2051 }
2052 
2066  QString(),
2067  QStringView(),
2069  QRegularExpression::NoMatchOption))
2070 {
2071  d->isValid = true;
2072 }
2073 
2078 {
2079 }
2080 
2082 
2083 
2089  : d(match.d)
2090 {
2091 }
2092 
2112 {
2113  d = match.d;
2114  return *this;
2115 }
2116 
2139  : d(&dd)
2140 {
2141 }
2142 
2150 {
2151  return d->regularExpression;
2152 }
2153 
2154 
2163 {
2164  return d->matchType;
2165 }
2166 
2174 QRegularExpression::MatchOptions QRegularExpressionMatch::matchOptions() const
2175 {
2176  return d->matchOptions;
2177 }
2178 
2194 {
2195  return d->capturedCount - 1;
2196 }
2197 
2220 {
2221  const int nth = d->regularExpression.d->captureIndexForName(name);
2222  return hasCaptured(nth);
2223 }
2224 
2248 {
2249  if (nth < 0 || nth > lastCapturedIndex())
2250  return false;
2251 
2252  return d->capturedOffsets.at(nth * 2) != -1;
2253 }
2254 
2268 {
2269  return capturedView(nth).toString();
2270 }
2271 
2287 {
2288  if (!hasCaptured(nth))
2289  return QStringView();
2290 
2291  qsizetype start = capturedStart(nth);
2292 
2293  if (start == -1) // didn't capture
2294  return QStringView();
2295 
2296  return d->subject.mid(start, capturedLength(nth));
2297 }
2298 
2322 {
2323  if (name.isEmpty()) {
2324  qWarning("QRegularExpressionMatch::captured: empty capturing group name passed");
2325  return QString();
2326  }
2327 
2328  return capturedView(name).toString();
2329 }
2330 
2344 {
2345  if (name.isEmpty()) {
2346  qWarning("QRegularExpressionMatch::capturedView: empty capturing group name passed");
2347  return QStringView();
2348  }
2349  int nth = d->regularExpression.d->captureIndexForName(name);
2350  if (nth == -1)
2351  return QStringView();
2352  return capturedView(nth);
2353 }
2354 
2362 {
2363  QStringList texts;
2364  texts.reserve(d->capturedCount);
2365  for (int i = 0; i < d->capturedCount; ++i)
2366  texts << captured(i);
2367  return texts;
2368 }
2369 
2379 {
2380  if (!hasCaptured(nth))
2381  return -1;
2382 
2383  return d->capturedOffsets.at(nth * 2);
2384 }
2385 
2395 {
2396  // bound checking performed by these two functions
2397  return capturedEnd(nth) - capturedStart(nth);
2398 }
2399 
2408 {
2409  if (!hasCaptured(nth))
2410  return -1;
2411 
2412  return d->capturedOffsets.at(nth * 2 + 1);
2413 }
2414 
2457 {
2458  if (name.isEmpty()) {
2459  qWarning("QRegularExpressionMatch::capturedStart: empty capturing group name passed");
2460  return -1;
2461  }
2462  int nth = d->regularExpression.d->captureIndexForName(name);
2463  if (nth == -1)
2464  return -1;
2465  return capturedStart(nth);
2466 }
2467 
2480 {
2481  if (name.isEmpty()) {
2482  qWarning("QRegularExpressionMatch::capturedLength: empty capturing group name passed");
2483  return 0;
2484  }
2485  int nth = d->regularExpression.d->captureIndexForName(name);
2486  if (nth == -1)
2487  return 0;
2488  return capturedLength(nth);
2489 }
2490 
2502 {
2503  if (name.isEmpty()) {
2504  qWarning("QRegularExpressionMatch::capturedEnd: empty capturing group name passed");
2505  return -1;
2506  }
2507  int nth = d->regularExpression.d->captureIndexForName(name);
2508  if (nth == -1)
2509  return -1;
2510  return capturedEnd(nth);
2511 }
2512 
2520 {
2521  return d->hasMatch;
2522 }
2523 
2535 {
2536  return d->hasPartialMatch;
2537 }
2538 
2547 {
2548  return d->isValid;
2549 }
2550 
2555  : d(&dd)
2556 {
2557 }
2558 
2574  QRegularExpression::NoMatchOption,
2576 {
2577 }
2578 
2583 {
2584 }
2585 
2587 
2588 
2595  : d(iterator.d)
2596 {
2597 }
2598 
2618 {
2619  d = iterator.d;
2620  return *this;
2621 }
2622 
2650 {
2651  return d->next.isValid();
2652 }
2653 
2661 {
2662  return d->hasNext();
2663 }
2664 
2672 {
2673  if (!hasNext())
2674  qWarning("QRegularExpressionMatchIterator::peekNext() called on an iterator already at end");
2675 
2676  return d->next;
2677 }
2678 
2686 {
2687  if (!hasNext()) {
2688  qWarning("QRegularExpressionMatchIterator::next() called on an iterator already at end");
2689  return d.constData()->next;
2690  }
2691 
2692  d.detach();
2693  return qExchange(d->next, d->next.d.constData()->nextMatch());
2694 }
2695 
2703 {
2704  return d->regularExpression;
2705 }
2706 
2715 {
2716  return d->matchType;
2717 }
2718 
2726 QRegularExpression::MatchOptions QRegularExpressionMatchIterator::matchOptions() const
2727 {
2728  return d->matchOptions;
2729 }
2730 
2735 {
2737 }
2738 
2744 #ifndef QT_NO_DATASTREAM
2753 {
2754  out << re.pattern() << quint32(re.patternOptions().toInt());
2755  return out;
2756 }
2757 
2766 {
2767  QString pattern;
2768  quint32 patternOptions;
2769  in >> pattern >> patternOptions;
2770  re.setPattern(pattern);
2771  re.setPatternOptions(QRegularExpression::PatternOptions::fromInt(patternOptions));
2772  return in;
2773 }
2774 #endif
2775 
2776 #ifndef QT_NO_DEBUG_STREAM
2786 {
2787  QDebugStateSaver saver(debug);
2788  debug.nospace() << "QRegularExpression(" << re.pattern() << ", " << re.patternOptions() << ')';
2789  return debug;
2790 }
2791 
2800 QDebug operator<<(QDebug debug, QRegularExpression::PatternOptions patternOptions)
2801 {
2802  QDebugStateSaver saver(debug);
2803  QByteArray flags;
2804 
2805  if (patternOptions == QRegularExpression::NoPatternOption) {
2806  flags = "NoPatternOption";
2807  } else {
2808  flags.reserve(200); // worst case...
2809  if (patternOptions & QRegularExpression::CaseInsensitiveOption)
2810  flags.append("CaseInsensitiveOption|");
2812  flags.append("DotMatchesEverythingOption|");
2813  if (patternOptions & QRegularExpression::MultilineOption)
2814  flags.append("MultilineOption|");
2816  flags.append("ExtendedPatternSyntaxOption|");
2817  if (patternOptions & QRegularExpression::InvertedGreedinessOption)
2818  flags.append("InvertedGreedinessOption|");
2819  if (patternOptions & QRegularExpression::DontCaptureOption)
2820  flags.append("DontCaptureOption|");
2822  flags.append("UseUnicodePropertiesOption|");
2823  flags.chop(1);
2824  }
2825 
2826  debug.nospace() << "QRegularExpression::PatternOptions(" << flags << ')';
2827 
2828  return debug;
2829 }
2839 {
2840  QDebugStateSaver saver(debug);
2841  debug.nospace() << "QRegularExpressionMatch(";
2842 
2843  if (!match.isValid()) {
2844  debug << "Invalid)";
2845  return debug;
2846  }
2847 
2848  debug << "Valid";
2849 
2850  if (match.hasMatch()) {
2851  debug << ", has match: ";
2852  for (int i = 0; i <= match.lastCapturedIndex(); ++i) {
2853  debug << i
2854  << ":(" << match.capturedStart(i) << ", " << match.capturedEnd(i)
2855  << ", " << match.captured(i) << ')';
2856  if (i < match.lastCapturedIndex())
2857  debug << ", ";
2858  }
2859  } else if (match.hasPartialMatch()) {
2860  debug << ", has partial match: ("
2861  << match.capturedStart(0) << ", "
2862  << match.capturedEnd(0) << ", "
2863  << match.captured(0) << ')';
2864  } else {
2865  debug << ", no match";
2866  }
2867 
2868  debug << ')';
2869 
2870  return debug;
2871 }
2872 #endif
2873 
2874 // fool lupdate: make it extract those strings for translation, but don't put them
2875 // inside Qt -- they're already inside libpcre (cf. man 3 pcreapi, pcre_compile.c).
2876 #if 0
2877 
2878 /* PCRE is a library of functions to support regular expressions whose syntax
2879 and semantics are as close as possible to those of the Perl 5 language.
2880 
2881  Written by Philip Hazel
2882  Original API code Copyright (c) 1997-2012 University of Cambridge
2883  New API code Copyright (c) 2015 University of Cambridge
2884 
2885 -----------------------------------------------------------------------------
2886 Redistribution and use in source and binary forms, with or without
2887 modification, are permitted provided that the following conditions are met:
2888 
2889  * Redistributions of source code must retain the above copyright notice,
2890  this list of conditions and the following disclaimer.
2891 
2892  * Redistributions in binary form must reproduce the above copyright
2893  notice, this list of conditions and the following disclaimer in the
2894  documentation and/or other materials provided with the distribution.
2895 
2896  * Neither the name of the University of Cambridge nor the names of its
2897  contributors may be used to endorse or promote products derived from
2898  this software without specific prior written permission.
2899 
2900 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2901 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2902 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2903 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2904 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2905 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2906 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2907 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2908 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2909 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2910 POSSIBILITY OF SUCH DAMAGE.
2911 -----------------------------------------------------------------------------
2912 */
2913 
2914 static const char *pcreCompileErrorCodes[] =
2915 {
2916  QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
2917  QT_TRANSLATE_NOOP("QRegularExpression", "\\ at end of pattern"),
2918  QT_TRANSLATE_NOOP("QRegularExpression", "\\c at end of pattern"),
2919  QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character follows \\"),
2920  QT_TRANSLATE_NOOP("QRegularExpression", "numbers out of order in {} quantifier"),
2921  QT_TRANSLATE_NOOP("QRegularExpression", "number too big in {} quantifier"),
2922  QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating ] for character class"),
2923  QT_TRANSLATE_NOOP("QRegularExpression", "escape sequence is invalid in character class"),
2924  QT_TRANSLATE_NOOP("QRegularExpression", "range out of order in character class"),
2925  QT_TRANSLATE_NOOP("QRegularExpression", "quantifier does not follow a repeatable item"),
2926  QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unexpected repeat"),
2927  QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (? or (?-"),
2928  QT_TRANSLATE_NOOP("QRegularExpression", "POSIX named classes are supported only within a class"),
2929  QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
2930  QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis"),
2931  QT_TRANSLATE_NOOP("QRegularExpression", "reference to non-existent subpattern"),
2932  QT_TRANSLATE_NOOP("QRegularExpression", "pattern passed as NULL"),
2933  QT_TRANSLATE_NOOP("QRegularExpression", "unrecognised compile-time option bit(s)"),
2934  QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after (?# comment"),
2935  QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
2936  QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too large"),
2937  QT_TRANSLATE_NOOP("QRegularExpression", "failed to allocate heap memory"),
2938  QT_TRANSLATE_NOOP("QRegularExpression", "unmatched closing parenthesis"),
2939  QT_TRANSLATE_NOOP("QRegularExpression", "internal error: code overflow"),
2940  QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis for condition"),
2941  QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is not fixed length"),
2942  QT_TRANSLATE_NOOP("QRegularExpression", "a relative value of zero is not allowed"),
2943  QT_TRANSLATE_NOOP("QRegularExpression", "conditional subpattern contains more than two branches"),
2944  QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?( or (?(?C)"),
2945  QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+ or (?-"),
2946  QT_TRANSLATE_NOOP("QRegularExpression", "unknown POSIX class name"),
2947  QT_TRANSLATE_NOOP("QRegularExpression", "internal error in pcre2_study(): should not occur"),
2948  QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have Unicode support"),
2949  QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"),
2950  QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\x{} or \\o{} is too large"),
2951  QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind is too complicated"),
2952  QT_TRANSLATE_NOOP("QRegularExpression", "\\C is not allowed in a lookbehind assertion in UTF-" "16" " mode"),
2953  QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2 does not support \\F, \\L, \\l, \\N{name}, \\U, or \\u"),
2954  QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is greater than 255"),
2955  QT_TRANSLATE_NOOP("QRegularExpression", "closing parenthesis for (?C expected"),
2956  QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in (*VERB) name"),
2957  QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?P"),
2958  QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in subpattern name (missing terminator?)"),
2959  QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name (PCRE2_DUPNAMES not set)"),
2960  QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name must start with a non-digit"),
2961  QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have support for \\P, \\p, or \\X"),
2962  QT_TRANSLATE_NOOP("QRegularExpression", "malformed \\P or \\p sequence"),
2963  QT_TRANSLATE_NOOP("QRegularExpression", "unknown property name after \\P or \\p"),
2964  QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum " "32" " code units)"),
2965  QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum " "10000" ")"),
2966  QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"),
2967  QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 in 8-bit non-UTF-8 mode"),
2968  QT_TRANSLATE_NOOP("QRegularExpression", "internal error: overran compiling workspace"),
2969  QT_TRANSLATE_NOOP("QRegularExpression", "internal error: previously-checked referenced subpattern not found"),
2970  QT_TRANSLATE_NOOP("QRegularExpression", "DEFINE subpattern contains more than one branch"),
2971  QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"),
2972  QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown newline setting"),
2973  QT_TRANSLATE_NOOP("QRegularExpression", "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number"),
2974  QT_TRANSLATE_NOOP("QRegularExpression", "(?R (recursive pattern call) must be followed by a closing parenthesis"),
2975  QT_TRANSLATE_NOOP("QRegularExpression", "obsolete error (should not occur)"),
2976  QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized or malformed"),
2977  QT_TRANSLATE_NOOP("QRegularExpression", "subpattern number is too big"),
2978  QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name expected"),
2979  QT_TRANSLATE_NOOP("QRegularExpression", "internal error: parsed pattern overflow"),
2980  QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"),
2981  QT_TRANSLATE_NOOP("QRegularExpression", "different names for subpatterns of the same number are not allowed"),
2982  QT_TRANSLATE_NOOP("QRegularExpression", "(*MARK) must have an argument"),
2983  QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
2984  QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a printable ASCII character"),
2985  QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a letter or one of [\\]^_?"),
2986  QT_TRANSLATE_NOOP("QRegularExpression", "\\k is not followed by a braced, angle-bracketed, or quoted name"),
2987  QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown meta code in check_lookbehinds()"),
2988  QT_TRANSLATE_NOOP("QRegularExpression", "\\N is not supported in a class"),
2989  QT_TRANSLATE_NOOP("QRegularExpression", "callout string is too long"),
2990  QT_TRANSLATE_NOOP("QRegularExpression", "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)"),
2991  QT_TRANSLATE_NOOP("QRegularExpression", "using UTF is disabled by the application"),
2992  QT_TRANSLATE_NOOP("QRegularExpression", "using UCP is disabled by the application"),
2993  QT_TRANSLATE_NOOP("QRegularExpression", "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)"),
2994  QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\u.... sequence is too large"),
2995  QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{} or \\N{U+}"),
2996  QT_TRANSLATE_NOOP("QRegularExpression", "syntax error or number too big in (?(VERSION condition"),
2997  QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in auto_possessify()"),
2998  QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating delimiter for callout with string argument"),
2999  QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized string delimiter follows (?C"),
3000  QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled by the application"),
3001  QT_TRANSLATE_NOOP("QRegularExpression", "(?| and/or (?J: or (?x: parentheses are too deeply nested"),
3002  QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled in this PCRE2 library"),
3003  QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too complicated"),
3004  QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is too long"),
3005  QT_TRANSLATE_NOOP("QRegularExpression", "pattern string is longer than the limit set by the application"),
3006  QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown code in parsed pattern"),
3007  QT_TRANSLATE_NOOP("QRegularExpression", "internal error: bad code value in parsed_skip()"),
3008  QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode"),
3009  QT_TRANSLATE_NOOP("QRegularExpression", "invalid option bits with PCRE2_LITERAL"),
3010  QT_TRANSLATE_NOOP("QRegularExpression", "\\N{U+dddd} is supported only in Unicode (UTF) mode"),
3011  QT_TRANSLATE_NOOP("QRegularExpression", "invalid hyphen in option setting"),
3012  QT_TRANSLATE_NOOP("QRegularExpression", "(*alpha_assertion) not recognized"),
3013  QT_TRANSLATE_NOOP("QRegularExpression", "script runs require Unicode support, which this version of PCRE2 does not have"),
3014  QT_TRANSLATE_NOOP("QRegularExpression", "too many capturing groups (maximum 65535)"),
3015  QT_TRANSLATE_NOOP("QRegularExpression", "atomic assertion expected after (?( or (?(?C)"),
3016  QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
3017  QT_TRANSLATE_NOOP("QRegularExpression", "no match"),
3018  QT_TRANSLATE_NOOP("QRegularExpression", "partial match"),
3019  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 1 byte missing at end"),
3020  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 2 bytes missing at end"),
3021  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 3 bytes missing at end"),
3022  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 4 bytes missing at end"),
3023  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5 bytes missing at end"),
3024  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 2 top bits not 0x80"),
3025  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 3 top bits not 0x80"),
3026  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 4 top bits not 0x80"),
3027  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 5 top bits not 0x80"),
3028  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 6 top bits not 0x80"),
3029  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5-byte character is not allowed (RFC 3629)"),
3030  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 6-byte character is not allowed (RFC 3629)"),
3031  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points greater than 0x10ffff are not defined"),
3032  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points 0xd800-0xdfff are not defined"),
3033  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 2-byte sequence"),
3034  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 3-byte sequence"),
3035  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 4-byte sequence"),
3036  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 5-byte sequence"),
3037  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 6-byte sequence"),
3038  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: isolated byte with 0x80 bit set"),
3039  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: illegal byte (0xfe or 0xff)"),
3040  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: missing low surrogate at end"),
3041  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: invalid low surrogate"),
3042  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: isolated low surrogate"),
3043  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points 0xd800-0xdfff are not defined"),
3044  QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points greater than 0x10ffff are not defined"),
3045  QT_TRANSLATE_NOOP("QRegularExpression", "bad data value"),
3046  QT_TRANSLATE_NOOP("QRegularExpression", "patterns do not all use the same character tables"),
3047  QT_TRANSLATE_NOOP("QRegularExpression", "magic number missing"),
3048  QT_TRANSLATE_NOOP("QRegularExpression", "pattern compiled in wrong mode: 8/16/32-bit error"),
3049  QT_TRANSLATE_NOOP("QRegularExpression", "bad offset value"),
3050  QT_TRANSLATE_NOOP("QRegularExpression", "bad option value"),
3051  QT_TRANSLATE_NOOP("QRegularExpression", "invalid replacement string"),
3052  QT_TRANSLATE_NOOP("QRegularExpression", "bad offset into UTF string"),
3053  QT_TRANSLATE_NOOP("QRegularExpression", "callout error code"),
3054  QT_TRANSLATE_NOOP("QRegularExpression", "invalid data in workspace for DFA restart"),
3055  QT_TRANSLATE_NOOP("QRegularExpression", "too much recursion for DFA matching"),
3056  QT_TRANSLATE_NOOP("QRegularExpression", "backreference condition or recursion test is not supported for DFA matching"),
3057  QT_TRANSLATE_NOOP("QRegularExpression", "function is not supported for DFA matching"),
3058  QT_TRANSLATE_NOOP("QRegularExpression", "pattern contains an item that is not supported for DFA matching"),
3059  QT_TRANSLATE_NOOP("QRegularExpression", "workspace size exceeded in DFA matching"),
3060  QT_TRANSLATE_NOOP("QRegularExpression", "internal error - pattern overwritten?"),
3061  QT_TRANSLATE_NOOP("QRegularExpression", "bad JIT option"),
3062  QT_TRANSLATE_NOOP("QRegularExpression", "JIT stack limit reached"),
3063  QT_TRANSLATE_NOOP("QRegularExpression", "match limit exceeded"),
3064  QT_TRANSLATE_NOOP("QRegularExpression", "no more memory"),
3065  QT_TRANSLATE_NOOP("QRegularExpression", "unknown substring"),
3066  QT_TRANSLATE_NOOP("QRegularExpression", "non-unique substring name"),
3067  QT_TRANSLATE_NOOP("QRegularExpression", "NULL argument passed"),
3068  QT_TRANSLATE_NOOP("QRegularExpression", "nested recursion at the same subject position"),
3069  QT_TRANSLATE_NOOP("QRegularExpression", "matching depth limit exceeded"),
3070  QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not available"),
3071  QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not set"),
3072  QT_TRANSLATE_NOOP("QRegularExpression", "offset limit set without PCRE2_USE_OFFSET_LIMIT"),
3073  QT_TRANSLATE_NOOP("QRegularExpression", "bad escape sequence in replacement string"),
3074  QT_TRANSLATE_NOOP("QRegularExpression", "expected closing curly bracket in replacement string"),
3075  QT_TRANSLATE_NOOP("QRegularExpression", "bad substitution in replacement string"),
3076  QT_TRANSLATE_NOOP("QRegularExpression", "match with end before start or start moved backwards is not supported"),
3077  QT_TRANSLATE_NOOP("QRegularExpression", "too many replacements (more than INT_MAX)"),
3078  QT_TRANSLATE_NOOP("QRegularExpression", "bad serialized data"),
3079  QT_TRANSLATE_NOOP("QRegularExpression", "heap limit exceeded"),
3080  QT_TRANSLATE_NOOP("QRegularExpression", "invalid syntax"),
3081  QT_TRANSLATE_NOOP("QRegularExpression", "internal error - duplicate substitution match"),
3082  QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching")
3083 };
3084 #endif // #if 0
3085 
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
int toInt(bool *ok=nullptr, int base=10) const
bool isEmpty() const noexcept
Definition: qbytearray.h:129
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
@ Null
Definition: qchar.h:87
constexpr bool isLowSurrogate() const noexcept
Definition: qchar.h:511
constexpr bool isHighSurrogate() const noexcept
Definition: qchar.h:510
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
The QDataStream class provides serialization of binary data to a QIODevice.
Definition: qdatastream.h:66
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:65
Convenience class for custom QDebug operators.
Definition: qdebug.h:176
T * data() const noexcept
Definition: qshareddata.h:171
const T * constData() const noexcept
Definition: qshareddata.h:173
template< typename Enum > size_t qHash(QFlags< Enum > flags, size_t seed=0) noexcept
template< typename... T > size_t qHashMulti(size_t seed, const T &...args)
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
pointer data()
Definition: qlist.h:442
void resize(qsizetype size)
Definition: qlist.h:420
void clear()
Definition: qlist.h:445
The QMutex class provides access serialization between threads.
Definition: qmutex.h:285
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes.
Definition: qmutex.h:317
pcre2_jit_stack_16 * stack
The QRegularExpression class provides pattern matching using regular expressions.
PatternOptions patternOptions() const
friend class QRegularExpressionMatch
void setPatternOptions(PatternOptions options)
QDataStream & operator<<(QDataStream &out, const QRegularExpression &re)
qsizetype patternErrorOffset() const
static QString escape(const QString &str)
QDataStream & operator>>(QDataStream &in, QRegularExpression &re)
static QRegularExpression fromWildcard(QStringView pattern, Qt::CaseSensitivity cs=Qt::CaseInsensitive, WildcardConversionOptions options=DefaultWildcardConversion)
void setPattern(const QString &pattern)
QStringList namedCaptureGroups() const
friend struct QRegularExpressionMatchPrivate
friend class QRegularExpressionMatchIterator
bool operator==(const QRegularExpression &re) const
QRegularExpressionMatch match(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
QDebug operator<<(QDebug debug, QRegularExpression::PatternOptions patternOptions)
QString errorString() const
QRegularExpressionMatchIterator globalMatch(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
static QString anchoredPattern(const QString &expression)
static QString wildcardToRegularExpression(const QString &str, WildcardConversionOptions options=DefaultWildcardConversion)
QDebug operator<<(QDebug debug, const QRegularExpression &re)
The QRegularExpressionMatch class provides the results of a matching a QRegularExpression against a s...
QRegularExpression::MatchOptions matchOptions() const
QStringView capturedView(int nth=0) const
qsizetype capturedEnd(int nth=0) const
QRegularExpression::MatchType matchType() const
bool hasCaptured(const QString &name) const
QStringList capturedTexts() const
qsizetype capturedStart(int nth=0) const
qsizetype capturedLength(int nth=0) const
QRegularExpressionMatch & operator=(const QRegularExpressionMatch &match)
QString captured(int nth=0) const
QRegularExpression regularExpression() const
QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match)
The QRegularExpressionMatchIterator class provides an iterator on the results of a global match of a ...
QRegularExpressionMatchIterator & operator=(const QRegularExpressionMatchIterator &iterator)
QRegularExpression::MatchOptions matchOptions() const
QRegularExpressionMatch peekNext() const
QRegularExpression::MatchType matchType() const
QRegularExpression regularExpression() const
The QSharedData class is a base class for shared data objects. \reentrant.
Definition: qshareddata.h:55
The QString class provides a Unicode character string.
Definition: qstring.h:388
static QString fromUtf16(const char16_t *, qsizetype size=-1)
Definition: qstring.cpp:5658
qsizetype size() const
Definition: qstring.h:413
const QChar at(qsizetype i) const
Definition: qstring.h:1212
QChar * data()
Definition: qstring.h:1228
qsizetype length() const
Definition: qstring.h:415
void resize(qsizetype size)
Definition: qstring.cpp:2670
The QStringList class provides a list of strings.
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
Definition: qstringview.h:122
constexpr const storage_type * utf16() const noexcept
Definition: qstringview.h:242
constexpr qsizetype size() const noexcept
Definition: qstringview.h:239
QString toString() const
Definition: qstring.h:1165
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Definition: qstringview.h:261
The QThreadStorage class provides per-thread data storage.
float rx
QString str
[2]
#define true
Definition: ftrandom.c:51
auto it unsigned count const
Definition: hb-iter.hh:848
short next
Definition: keywords.cpp:454
typename C::iterator iterator
CaseSensitivity
Definition: qnamespace.h:1282
@ CaseSensitive
Definition: qnamespace.h:1284
#define QString()
Definition: parse-defines.h:51
#define PCRE2_INFO_CAPTURECOUNT
Definition: pcre2.h:410
#define PCRE2_ANCHORED
Definition: pcre2.h:105
#define PCRE2_NOTEMPTY_ATSTART
Definition: pcre2.h:173
#define PCRE2_CONFIG_NEWLINE
Definition: pcre2.h:442
#define PCRE2_UNSET
Definition: pcre2.h:474
#define PCRE2_INFO_NAMETABLE
Definition: pcre2.h:425
#define PCRE2_ERROR_NOMATCH
Definition: pcre2.h:320
#define PCRE2_UCP
Definition: pcre2.h:136
#define PCRE2_DOTALL
Definition: pcre2.h:124
#define PCRE2_INFO_JCHANGED
Definition: pcre2.h:415
#define PCRE2_NEWLINE_ANYCRLF
Definition: pcre2.h:207
#define PCRE2_EXTENDED
Definition: pcre2.h:126
#define PCRE2_UNGREEDY
Definition: pcre2.h:137
#define PCRE2_SIZE
Definition: pcre2.h:471
#define PCRE2_PARTIAL_SOFT
Definition: pcre2.h:174
#define PCRE2_PARTIAL_HARD
Definition: pcre2.h:175
#define PCRE2_CASELESS
Definition: pcre2.h:122
#define PCRE2_ERROR_JIT_STACKLIMIT
Definition: pcre2.h:380
#define PCRE2_INFO_MAXLOOKBEHIND
Definition: pcre2.h:421
const PCRE2_UCHAR16 * PCRE2_SPTR16
Definition: pcre2.h:463
#define PCRE2_INFO_NEWLINE
Definition: pcre2.h:426
#define PCRE2_JIT_PARTIAL_HARD
Definition: pcre2.h:161
#define PCRE2_JIT_COMPLETE
Definition: pcre2.h:159
#define PCRE2_INFO_NAMECOUNT
Definition: pcre2.h:423
#define PCRE2_NEWLINE_CRLF
Definition: pcre2.h:205
#define PCRE2_MULTILINE
Definition: pcre2.h:129
#define PCRE2_NO_AUTO_CAPTURE
Definition: pcre2.h:132
#define PCRE2_JIT_PARTIAL_SOFT
Definition: pcre2.h:160
#define PCRE2_UTF
Definition: pcre2.h:138
#define PCRE2_NO_UTF_CHECK
Definition: pcre2.h:106
#define PCRE2_ERROR_PARTIAL
Definition: pcre2.h:321
#define PCRE2_NEWLINE_ANY
Definition: pcre2.h:206
#define PCRE2_INFO_NAMEENTRYSIZE
Definition: pcre2.h:424
#define Q_UNLIKELY(x)
#define Q_ASSUME(Expr)
QList< QString > QStringList
Definition: qcontainerfwd.h:64
unsigned int quint32
Definition: qglobal.h:288
ptrdiff_t qsizetype
Definition: qglobal.h:308
#define Q_DISABLE_COPY(Class)
Definition: qglobal.h:515
unsigned short ushort
Definition: qglobal.h:333
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qDebug
[1]
Definition: qlogging.h:177
#define qWarning
Definition: qlogging.h:179
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLuint64 key
GLuint index
[2]
GLenum GLenum GLsizei count
GLbitfield flags
GLuint start
GLenum GLuint GLintptr offset
GLuint name
const GLubyte * c
Definition: qopenglext.h:12701
GLuint in
Definition: qopenglext.h:8870
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLubyte * pattern
Definition: qopenglext.h:2744
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
#define QT_DEFINE_QESDP_SPECIALIZATION_DTOR(Class)
Definition: qshareddata.h:318
QTextStream out(stdout)
[7]
QObject::connect nullptr
QReadWriteLock lock
[0]
QSharedPointer< T > other(t)
[5]
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
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
Definition: inftrees.h:24
QMutex mutex