Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-3435

In a QRexExp, escaping metacharacter does not work in QRegExp::WildCard mode

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • Not Evaluated
    • 4.6.0
    • 4.4.3
    • GUI: Text handling
    • None
    • e7c36fc2e420f1cee4370020b9f50bb5a6dfe92a

    Description

      In the QRegExp::WildCard mode, it is not possible to escape the metacharacters. For example, "
      [.cpp" will not match "[.cpp".

      Here is a test case for this problem:

      #include <QtTest/QtTest>

      class Test : public QObject{
      Q_OBJECT

      private slots:
      void testEscapingWildcard_data()

      { QTest::addColumn<QString>("pattern"); QTest::addColumn<QString>("teststring"); QTest::addColumn<bool>("isMatching"); QTest::newRow("[ Not escaped") << "[Qt;" << "[Qt;" << false; QTest::newRow("[ Escaped") << "\\[Qt;" << "[Qt;" << true; QTest::newRow("] Not escaped") << "]Ik;" << "]Ik;" << false; QTest::newRow("] Escaped") << "\\]Ip;" << "]Ip;" << true; QTest::newRow("? Not escaped valid") << "?Ou:" << ".Ou:" << true; QTest::newRow("? Not escaped invalid") << "?Tr;" << "Tr;" << false; QTest::newRow("? Escaped") << "\\?O;" << "?O;" << true; QTest::newRow("[] not escaped") << "[lL]" << "l" << true; QTest::newRow("case [[]") << "[[abc]" << "[" << true; QTest::newRow("case []abc] match ]") << "[]abc]" << "]" << true; QTest::newRow("case []abc] match a") << "[]abc]" << "a" << true; QTest::newRow("case [abc] match a") << "[abc]" << "a" << true; QTest::newRow("case []] don't match [") << "[]abc]" << "[" << false; QTest::newRow("case [^]abc] match d") << "[^]abc]" << "d" << true; QTest::newRow("case [^]abc] don't match ]") << "[^]abc]" << "]" << false; QTest::newRow("* Not escaped with char") << "*Te;" << "12345Te;" << true; QTest::newRow("* Not escaped without char") << "*Ch;" << "Ch;" << true; QTest::newRow("* Not escaped invalid") << "*Ro;" << "o;" << false; QTest::newRow("* Escaped") << "\\[Cks;" << "[Cks;" << true; QTest::newRow("a true '\\' in input") << "\\Qt;" << "\\Qt;" << true; QTest::newRow("two true '\\' in input") << "\\\\Qt;" << "\\\\Qt;" << true; QTest::newRow("a '\\' at the end") << "\\\\Qt;" << "\\\\Qt;" << true; }

      void testEscapingWildcard()

      { QFETCH(QString, pattern); QRegExp re(pattern); re.setPatternSyntax(QRegExp::Wildcard); QFETCH(QString, teststring); QFETCH(bool, isMatching); QCOMPARE(re.exactMatch(teststring), isMatching); }

      void testInvalidWildcard_data()

      { QTest::addColumn<QString>("pattern"); QTest::addColumn<bool>("isValid"); QTest::newRow("valid []") << "[abc]" << true; QTest::newRow("invalid [") << "[abc" << false; QTest::newRow("ending [") << "abc[" << false; QTest::newRow("ending ]") << "abc]" << false; QTest::newRow("ending [^") << "abc[^" << false; QTest::newRow("ending [\\") << "abc[\\" << false; QTest::newRow("ending []") << "abc[]" << false; QTest::newRow("ending [[") << "abc[[" << false; }

      void testInvalidWildcard()

      { QFETCH(QString, pattern); QRegExp re(pattern); re.setPatternSyntax(QRegExp::Wildcard); QFETCH(bool, isValid); QCOMPARE(re.isValid(), isValid); }

      };

      QTEST_MAIN(Test)
      #include "test.moc"

      And here is a patch to solve the issue:

      diff --git a/src/corelib/tools/qregexp.cpp b/src/corelib/tools/qregexp.cpp
      index e93b003..61ee2e9 100644
      — a/src/corelib/tools/qregexp.cpp
      +++ b/src/corelib/tools/qregexp.cpp
      @@ -718,47 +718,98 @@ static void mergeInto(QVector<int> *a, const QVector<int> &b)
      */
      static QString wc2rx(const QString &wc_str)
      {

      • int wclen = wc_str.length();
        + const uint wclen = wc_str.length();
        QString rx;
      • int i = 0;
        + uint i = 0;
        + bool isEscaping = false; // the previous character is '\'
        const QChar *wc = wc_str.unicode();
        +
        while (i < wclen) {
      • QChar c = wc[i++];
        + const QChar c = wc[i++];
        switch (c.unicode()) {
        case '*':
      • rx += QLatin1String(".*");
        + if(isEscaping) { + rx += QLatin1String("\\*"); + isEscaping = false; + }

        else

        { + rx += QLatin1String(".*"); + }

        break;
        +
        case '?':

      • rx += QLatin1Char('.');
        + if(isEscaping) { + rx += QLatin1String("\\?"); + isEscaping = false; + }

        else

        { + rx += QLatin1Char('.'); + }

        +
        + break;
        +
        + case '
        ':
        + if(isEscaping)

        { + rx += QLatin1String("\\\\"); + }

        + if (i+1 == wclen)

        { // the end + rx += QLatin1String("\\\\"); + }

        + // we insert the
        later if necessary
        + isEscaping = true;
        +
        break;
        +
        case '$':
        case '(':
        case ')':
        case '+':
        case '.':

      • case '
        ':
        case '^':
        case ' {': case '|': case '}

        ':
        + if(isEscaping)

        { + isEscaping = false; + rx += QLatin1Char('\\'); + }

        rx += QLatin1Char('
        ');
        rx += c;
        break;
        +
        case '[':

      • rx += c;
      • if (wc[i] == QLatin1Char('^'))
      • rx += wc[i++];
      • if (i < wclen) {
      • if (rx[i] == QLatin1Char(']'))
        + if(isEscaping) { + isEscaping = false; + rx += QLatin1String("\\["); + }

        else{
        + rx += c;
        + // first ] is not a closing ]
        + if (i < wclen && wc[i] == QLatin1Char('^'))
        rx += wc[i++];

      • while (i < wclen && wc[i] != QLatin1Char(']')) { - if (wc[i] == QLatin1Char('\\')) - rx += QLatin1Char('\\'); + if (i < wclen && rx[i] == QLatin1Char(']')) rx += wc[i++]; - }

        +
        + const QLatin1Char escapeChar('
        ');
        + while (i < wclen && wc[i] != QLatin1Char(']'))

        { + if (wc[i] == escapeChar && (i+1 < wclen)) + rx += wc[i++]; + rx += wc[i++]; + }

        + if(i < wclen)
        + rx += wc[i++];
        + }
        + break;
        + case ']':
        + if(isEscaping)

        { + isEscaping = false; + rx += QLatin1String("\\"); }

        + rx += c;
        break;
        +
        default:
        + if(isEscaping)

        { + isEscaping = false; + rx += QLatin1String("\\\\"); + }

        rx += c;
        }
        }

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            poulain Benjamin Poulain (closed Nokia identity) (Inactive)
            poulain Benjamin Poulain (closed Nokia identity) (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes