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. [SOLVED] Suggest a faster way for replacing custom parameters in a string
Forum Updated to NodeBB v4.3 + New Features

[SOLVED] Suggest a faster way for replacing custom parameters in a string

Scheduled Pinned Locked Moved General and Desktop
15 Posts 5 Posters 4.2k Views 4 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.
  • T3STYT Offline
    T3STYT Offline
    T3STY
    wrote on last edited by T3STY
    #1

    I have a class that should print a message with a certain string formatting. I'm using custom parameters defined with %$ where $ is any aA-zZ character. So a formatted string should look like "the sum of %a and %b is %c".
    My way of implementing the parameter replacing is simply to use QString::replace("%$", 5) for each parameter. However, I need to add some extra html formatting tags ( <b>, <i>, ect...) for each tag, and that makes it a way heavier task.

    Do you know a faster way of replacing those parameters and adding those tags for each? Maybe, did I miss any QString method that could do all the replacements at once, faster ?

    p.s. I know about QString().arg(), but that requires me to know in advance the number of parameters a formatted string would have, which in this application is not the case. Also, unspecified arguments that are not replaced (say I only use 5 arguments of 10 available) will remain as %6, %7 and so on, which is definitely an unwanted behavior.

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      Can you show an example of string that your are building ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • T3STYT Offline
        T3STYT Offline
        T3STY
        wrote on last edited by T3STY
        #3

        The string could be anything, really. It could include any number of parameters and other text. This is one:

        "[%HH:%mm:%s.%zzz] operation completed (%EE) %M"
        

        And that's the code I'm using at the moment:

        void consoleWidget::print(QVariant message, errorLevel EL){
            // using a QVariant to allow printing both strings and numeric data types 
            // get current local time
            QTime curTime(QTime::currentTime());
            
            // error level messages; el_msg[0] must not be empty (using a space) to prevent QString::at() crashing the application ->
            const QString el_msg[4] = {" ", "info", "warning", "error"};
            
            // replace parameters with data with the format specified in _format
            // _format is a private (pointer to) QString storing the message format to print, such as:
            // "[%HH:%mm:%s.%zzz] operation completed (%EE) %M"
            QString tmpMsg(*_format);
            // hour, leading zero, 00-23 or 01-12AM/PM
            tmpMsg.replace("%hh", curTime.toString("hh"));
            // hour, 0-23 or 1-12AM/PM
            tmpMsg.replace("%h",  curTime.toString("h") );
            // hour, 0-23
            tmpMsg.replace("%HH", curTime.toString("HH"));
            // minutes, 0-59
            tmpMsg.replace("%H",  curTime.toString("H") );
            // minutes, leading 0, 00-59
            tmpMsg.replace("%mm", curTime.toString("mm"));
            // hour, leading 0, 00-23
            tmpMsg.replace("%m",  curTime.toString("m") );
            // seconds, leading 0, 00-59
            tmpMsg.replace("%ss", curTime.toString("ss"));
            // seconds, 0-59
            tmpMsg.replace("%s",  curTime.toString("s") );
            // milliseconds, leading 0, 000-999
            tmpMsg.replace("%zzz",curTime.toString("zzz"));
            // milliseconds, 0-999
            tmpMsg.replace("%z",  curTime.toString("z") );
            // am/pm (lowercase)
            tmpMsg.replace("%a",  curTime.toString("a") );
            // AM/PM (UPPERCASE)
            tmpMsg.replace("%A",  curTime.toString("A") );
            // timezone
            tmpMsg.replace("%t",  curTime.toString("t") );
            
            // error level, lowercase, extended:    error, warning, info, (empty)
            tmpMsg.replace("%ee",  el_msg[EL]);
            // error level, lowercase, abbreviated: e, w, i, (empty)
            tmpMsg.replace("%e" ,  el_msg[EL].at(0));
            // error level, UPPERCASE, extended:    ERROR, WARNING, INFO, (empty)
            tmpMsg.replace("%EE",  el_msg[EL].toUpper());
            // error level, UPPERCASE, abbreviated: E, W, I, (empty)
            tmpMsg.replace("%E" ,  el_msg[EL].at(0).toUpper());
            
            // replace user message parameter with data
            // Most QVariant stored types can be converted to QString, it's safe not to check for conversion availability
            tmpMsg.replace("%M", message.toString());
            
            // will be replaced with appendHtml()
            this->appendPlainText(tmpMsg);
        }
        
        1 Reply Last reply
        0
        • mrjjM Offline
          mrjjM Offline
          mrjj
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @T3STY said:

          "[%HH:%mm:%s.%zzz] operation completed (%EE) %M"

          If that is a typically length of your source string then something like

          tmpMsg.replace("%a", " <b>" + curTime.toString("a") + "</b>");

          Should be fast enough ?
          Or Am I completely misunderstanding the question ?

          1 Reply Last reply
          0
          • T3STYT Offline
            T3STYT Offline
            T3STY
            wrote on last edited by T3STY
            #5

            That is what I was thinking to use. However, I was asking if there was anything that would replace all the parameters at once.
            Replacing strings so many times with QString::replace() causes a lot of memory reallocation in order to expand the string size to fit requirements, which also causes more CPU usage. While increasing the string size to twice every allocation is fast enough, doing so 3 or 4 times for 30 strings causes a huge performance loss.
            So, if there was any way to tell QString::replace() (or some other method) about more things to replace at once I think it would definitely be faster and cheaper for the memory.

            BTW, The format string could be made of even 20 parameters with extra (non parametric) words. Consider:

            "h: %h | hh: %hh | H: %h | HH: %HH | m: %m | mm: %mm | s: %s | ss: %ss | z: %z | zzz: %zzz | a: %a | A: %A |  | t: %t | e: %e | E: %E | ee: %ee | EE: %EE |  | %M"
            

            which includes only part of the parameters I want to implement. Also %M is a user message that could be even hundred of characters long. There is no typical string length that I could consider to reserve memory in advance.

            1 Reply Last reply
            0
            • Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #6

              I'd say sum up the total length of the parameters and call reserve on the string before doing the replacements.

              1 Reply Last reply
              1
              • T3STYT Offline
                T3STYT Offline
                T3STY
                wrote on last edited by
                #7

                That's a good idea! Thanks :)
                But it will still not solve the number replacements I should make... I have to think about some other strategy...

                O 1 Reply Last reply
                0
                • T3STYT T3STY

                  That's a good idea! Thanks :)
                  But it will still not solve the number replacements I should make... I have to think about some other strategy...

                  O Offline
                  O Offline
                  onek24
                  wrote on last edited by
                  #8

                  @T3STY

                  I can't provide any idea or solution, but maybe i can give you a hint - something i would try: Check out the source-code of the QString class and see what ::args(...) does. Maybe you can use Qt's code and implement the functionality to have different kinds of parameter-types(%s, %EE, ...).

                  1 Reply Last reply
                  0
                  • T3STYT Offline
                    T3STYT Offline
                    T3STY
                    wrote on last edited by
                    #9

                    Unfortunately, modifying Qt's source is not a viable option because of the license I'm using (LGPL). But I think I found some strategy to maintain some const-ness in the initial string length. I am using pre-formatted strings with "<FONT class="something">%1</FONT>" html tags, so most formatting is done with CSS ( QPlainTextEdit::document::setDefaultStyleSheet() ). This will reduce the number of reallocations (before replacement) to 1 (the %1 argument) with QString::arg(), and then I replace all data in the final string. I'm also thinking about other possible tricks like asking the time to QTime::getCurrentTime() with a separate string, so I would only replace time once instead of for each parameter.

                    O 1 Reply Last reply
                    0
                    • Chris KawaC Offline
                      Chris KawaC Offline
                      Chris Kawa
                      Lifetime Qt Champion
                      wrote on last edited by Chris Kawa
                      #10

                      But it will still not solve the number replacements I should make

                      You'll need to convert the numbers to strings anyway, so you can do that first and get the length of these strings.
                      The problem here is that numeric conversions in Qt like Qstring::number return a new string (thus allocate memory).
                      You could allocate a handful of QStrings once, reserve some space in them and then use QTextStream to make the conversions "in place".

                      1 Reply Last reply
                      0
                      • T3STYT Offline
                        T3STYT Offline
                        T3STY
                        wrote on last edited by
                        #11

                        @Chris-Kawa The number to string conversion is done via QVariant::toString() anyway, so that is not a problem. And reserving space is not necessary anymore if I use the tricks above :)

                        1 Reply Last reply
                        0
                        • T3STYT T3STY

                          Unfortunately, modifying Qt's source is not a viable option because of the license I'm using (LGPL). But I think I found some strategy to maintain some const-ness in the initial string length. I am using pre-formatted strings with "<FONT class="something">%1</FONT>" html tags, so most formatting is done with CSS ( QPlainTextEdit::document::setDefaultStyleSheet() ). This will reduce the number of reallocations (before replacement) to 1 (the %1 argument) with QString::arg(), and then I replace all data in the final string. I'm also thinking about other possible tricks like asking the time to QTime::getCurrentTime() with a separate string, so I would only replace time once instead of for each parameter.

                          O Offline
                          O Offline
                          onek24
                          wrote on last edited by onek24
                          #12

                          @T3STY said:

                          Unfortunately, modifying Qt's source is not a viable option because of the license I'm using (LGPL).

                          No need to modify Qt's source. Just check what Qt does in such a case and develop your own algorithm/method.

                          1 Reply Last reply
                          0
                          • SGaistS Offline
                            SGaistS Offline
                            SGaist
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            What about just doing a good old

                            QString message = "{" QTime::currentTime().toString() + el_msg[] etc.
                            

                            ?

                            Interested in AI ? www.idiap.ch
                            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                            1 Reply Last reply
                            0
                            • T3STYT Offline
                              T3STYT Offline
                              T3STY
                              wrote on last edited by
                              #14

                              @SGaist that would make it hard to follow a pre-format string. Yes, it would be faster and, to some extent, easier. But definitely not the solution in my case.

                              Anyway, eventually I went for the HTML pre-formatted strings method that I wrote about in an earlier post. It's the easier and faster solution for me and seems to have the lightest impact on performance of all methods I have tried.

                              Thank you all for help :)

                              1 Reply Last reply
                              0
                              • SGaistS Offline
                                SGaistS Offline
                                SGaist
                                Lifetime Qt Champion
                                wrote on last edited by
                                #15

                                If you want to be sure about the performance: QBENCHMARK ;)

                                Happy coding !

                                Interested in AI ? www.idiap.ch
                                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                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