Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Is there an easy way to count the number of occurrences of wildcards in a QString object?
Forum Updated to NodeBB v4.3 + New Features

Is there an easy way to count the number of occurrences of wildcards in a QString object?

Scheduled Pinned Locked Moved Solved General and Desktop
15 Posts 3 Posters 2.7k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Robert Hairgrove

    @Christian-Ehrlicher and @JonB : Thank you for the replies. I assume this means there is no built-in function, so I will try using a regular expression and count the matches.

    So far, this seems to work well enough as a pattern to capture any combination of 1 or 2 digits preceded by a single % character. If there are more than three digits following the token, only the first two are matched (QString::arg() can handle between 1 and 99 distinct wildcards according to the documentation, but I will certainly not need that many):

    (^[^%]?%\d{1,2})|([^%]%\d{1,2})
    

    Of course, the backslashes will need to be escaped, but it seems to work OK when tested on the site https://regex101.com. I can eliminate duplicates when I iterate over the matches.

    Can anyone come up with an example where this might break?

    JonBJ Online
    JonBJ Online
    JonB
    wrote on last edited by
    #5

    @Robert-Hairgrove
    Personally like I wrote I think I would scan with indexOf(), seems simpler to me than reg ex. May be personal preference!

    I think yours will go wrong on %%%1 etc.? Which is why I think it's trickier with a reg ex than your own code?

    R 1 Reply Last reply
    0
    • JonBJ JonB

      @Robert-Hairgrove
      Personally like I wrote I think I would scan with indexOf(), seems simpler to me than reg ex. May be personal preference!

      I think yours will go wrong on %%%1 etc.? Which is why I think it's trickier with a reg ex than your own code?

      R Offline
      R Offline
      Robert Hairgrove
      wrote on last edited by
      #6

      @JonB No, I tried this on the regex101 site. It was indeed a little tricky to get that part right, but here is the breakdown of the pattern:

      1st capturing group: Looks at the beginning of the string for any character not equal to %, or none, followed by exactly one % followed by 1 or 2 digits;

      2nd (alternate) capture group: Looks for a sequence which MUST begin with a non-% character followed by exactly one % followed by 1 or 2 digits.

      If the string begins with "%1" it will match the first group, but "%%1" does not match anywhere. Anything past the beginning of the string must match the second capture group, and this requires a % preceded by something else and followed by 1 or 2 digits, whereas the non-% character at the beginning of the string is optional (due to the "?" token).

      JonBJ 1 Reply Last reply
      0
      • R Robert Hairgrove

        @JonB No, I tried this on the regex101 site. It was indeed a little tricky to get that part right, but here is the breakdown of the pattern:

        1st capturing group: Looks at the beginning of the string for any character not equal to %, or none, followed by exactly one % followed by 1 or 2 digits;

        2nd (alternate) capture group: Looks for a sequence which MUST begin with a non-% character followed by exactly one % followed by 1 or 2 digits.

        If the string begins with "%1" it will match the first group, but "%%1" does not match anywhere. Anything past the beginning of the string must match the second capture group, and this requires a % preceded by something else and followed by 1 or 2 digits, whereas the non-% character at the beginning of the string is optional (due to the "?" token).

        JonBJ Online
        JonBJ Online
        JonB
        wrote on last edited by JonB
        #7

        @Robert-Hairgrove
        I don't understand what you are saying. I suggested what will not work:

        %%%1
        

        somewhere/anywhere (beginning/middle/end). That is 3 percent characters. It expands to a literal % followed by your %1 substitution. In my head your reg ex will fail to recognise the %1 because it will see it as a %%1 and so reject the match. Effectively you do not deal with %%s correctly.

        R 1 Reply Last reply
        0
        • JonBJ JonB

          @Robert-Hairgrove
          I don't understand what you are saying. I suggested what will not work:

          %%%1
          

          somewhere/anywhere (beginning/middle/end). That is 3 percent characters. It expands to a literal % followed by your %1 substitution. In my head your reg ex will fail to recognise the %1 because it will see it as a %%1 and so reject the match. Effectively you do not deal with %%s correctly.

          R Offline
          R Offline
          Robert Hairgrove
          wrote on last edited by Robert Hairgrove
          #8

          @JonB Hmmm ... I think you might be right about this. I was probably confusing the SQL LIKE syntax where "%" is also used as a wildcard, and to search for a literal "%" string, one must write it twice, i.e.: WHERE something LIKE '%%1' would match the string '%1' and WHERE something LIKE '%1' would match 'a1', 'b1' etc. So I was deliberately trying NOT to match the wildcard if it had two or more % tokens.

          In that case, the pattern would be much simpler: "%\d{1,2}" which would match anywhere in the string.

          JonBJ 1 Reply Last reply
          0
          • R Robert Hairgrove

            @JonB Hmmm ... I think you might be right about this. I was probably confusing the SQL LIKE syntax where "%" is also used as a wildcard, and to search for a literal "%" string, one must write it twice, i.e.: WHERE something LIKE '%%1' would match the string '%1' and WHERE something LIKE '%1' would match 'a1', 'b1' etc. So I was deliberately trying NOT to match the wildcard if it had two or more % tokens.

            In that case, the pattern would be much simpler: "%\d{1,2}" which would match anywhere in the string.

            JonBJ Online
            JonBJ Online
            JonB
            wrote on last edited by JonB
            #9

            @Robert-Hairgrove
            Sorry, but again I think you are misunderstanding.

            (Oh, btw, it may not be documented, but I believe Qt does do %% => % for arguments, and I have used that.)

            If you went for %\d{1,2} that would indeed incorrectly cause %%1 to be treated as %1 substitution. You are correct that you do need to deal with %1 versus %%1, as you tried earlier. But I believe you will go wrong on %%%1, you will see it as %%1 and thereby not thing it is a %1 but it is!

            Try abc %1 %%2 %%%3 %%%%4 def with whatever reg ex you choose. I have said I would probably not use reg exs here for this reason, I would just do it via indexOf('%', ...) and deal with the following characters (%, digits, something else) myself. But if you want to use reg ex here you'll have to deal with this issue!

            R 1 Reply Last reply
            0
            • Christian EhrlicherC Offline
              Christian EhrlicherC Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on last edited by
              #10

              I still don't understand the use-case for this though...
              If you want to see what Qt is doing search for findArgEscapes() in qstring.cpp

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              R 1 Reply Last reply
              0
              • Christian EhrlicherC Christian Ehrlicher

                I still don't understand the use-case for this though...
                If you want to see what Qt is doing search for findArgEscapes() in qstring.cpp

                R Offline
                R Offline
                Robert Hairgrove
                wrote on last edited by
                #11

                @Christian-Ehrlicher The use case would be like this: A function receives a pattern (a string with some wildcards) from some other place and needs to fill in the wildcards within the function, returning the completed string. My function would like to assert that the input has the expected number of wildcards before trying to do replacements.

                1 Reply Last reply
                0
                • JonBJ JonB

                  @Robert-Hairgrove
                  Sorry, but again I think you are misunderstanding.

                  (Oh, btw, it may not be documented, but I believe Qt does do %% => % for arguments, and I have used that.)

                  If you went for %\d{1,2} that would indeed incorrectly cause %%1 to be treated as %1 substitution. You are correct that you do need to deal with %1 versus %%1, as you tried earlier. But I believe you will go wrong on %%%1, you will see it as %%1 and thereby not thing it is a %1 but it is!

                  Try abc %1 %%2 %%%3 %%%%4 def with whatever reg ex you choose. I have said I would probably not use reg exs here for this reason, I would just do it via indexOf('%', ...) and deal with the following characters (%, digits, something else) myself. But if you want to use reg ex here you'll have to deal with this issue!

                  R Offline
                  R Offline
                  Robert Hairgrove
                  wrote on last edited by Robert Hairgrove
                  #12

                  @JonB I looked at the source code, as @Christian-Ehrlicher suggested, and it appears that QString("%%%1").arg("xyz") would result in the string "%%xyz", although I didn't try it yet.

                  JonBJ 1 Reply Last reply
                  0
                  • R Robert Hairgrove

                    @JonB I looked at the source code, as @Christian-Ehrlicher suggested, and it appears that QString("%%%1").arg("xyz") would result in the string "%%xyz", although I didn't try it yet.

                    JonBJ Online
                    JonBJ Online
                    JonB
                    wrote on last edited by JonB
                    #13

                    @Robert-Hairgrove

                    QString("%%%1").arg("xyz") would result in the string "%%xyz"

                    I would expect it to produce %xyz. But in any case the issue is I expect your code to miss the %1 in this case.

                    R 1 Reply Last reply
                    0
                    • JonBJ JonB

                      @Robert-Hairgrove

                      QString("%%%1").arg("xyz") would result in the string "%%xyz"

                      I would expect it to produce %xyz. But in any case the issue is I expect your code to miss the %1 in this case.

                      R Offline
                      R Offline
                      Robert Hairgrove
                      wrote on last edited by Robert Hairgrove
                      #14

                      @JonB Finally got around to setting up a little test app (with Qt 5.15.5 on Linux Ubuntu 18.04).
                      This is what it prints:

                      Original:  	Testing %%%1
                      Result:  	Testing %%xyz
                      

                      main.cpp

                      #include <QString>
                      #include <string>
                      #include <iostream>
                      
                      const QString s("Testing %%%1");
                      
                      int main()
                      {
                        const QString rep("xyz");
                        const QString res = s.arg(rep);
                        std::cout
                            << "Original:  \t" << s.toStdString()
                            << "\nResult:  \t" << res.toStdString()
                            << std::endl;
                        return 0;
                      }
                      

                      .pro file:

                      QT -= gui
                      
                      CONFIG += c++11 console
                      CONFIG -= app_bundle
                      
                      # You can make your code fail to compile if it uses deprecated APIs.
                      # In order to do so, uncomment the following line.
                      #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
                      
                      SOURCES += \
                              main.cpp
                      
                      # Default rules for deployment.
                      qnx: target.path = /tmp/$${TARGET}/bin
                      else: unix:!android: target.path = /opt/$${TARGET}/bin
                      !isEmpty(target.path): INSTALLS += target
                      
                      1 Reply Last reply
                      0
                      • R Offline
                        R Offline
                        Robert Hairgrove
                        wrote on last edited by
                        #15

                        Changed the regexp now to this:

                        %[1-9][0-9]?
                        

                        Just in case someone writes leading zeroes, i.e. "ABC %01 XYZ" instead of "ABC %1 XYZ". The question mark after the second brackets group is necessary for matching either single digits or two-digit numbers.

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved