Bug 218332 - No way to output '%1' in autoreplace
Summary: No way to output '%1' in autoreplace
Status: RESOLVED FIXED
Alias: None
Product: konversation
Classification: Applications
Component: general (show other bugs)
Version: Git
Platform: Compiled Sources Linux
: NOR normal
Target Milestone: ---
Assignee: Konversation Developers
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-12-11 22:49 UTC by Nicolás Alvarez
Modified: 2009-12-15 08:47 UTC (History)
0 users

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nicolás Alvarez 2009-12-11 22:49:11 UTC
In a regex autoreplace, it's impossible to output a literal percent sign followed by a number. If I have a regex "foo-(\S*)" and replacement "bar%23%1", "foo-x" will output "bar3x", because the %2 is interpreted as a capturing subpattern, even though the regex only has one subpattern.

The current code is:
 // replace %0 - %9 in regex groups
 for (int capture=0;capture<captures.count();capture++)
 {
     replacement.replace(QString("%%1").arg(capture),captures[capture]);
 }
 replacement.remove(QRegExp("%[0-9]"));

Removing the last line would allow the previous example to work. However, it still doesn't solve the problem if I *do* have a second subpattern (or if I want to output %1). What we really need is a way to escape the percent sign.

Instead of using replace(), I propose looping over the characters in the string. Pseudocode:
foreach (char in string) {
    if (char == %) {
        look at the following character;
        if (char == %) output += '%'; //this lets you escape a % by doubling it
        if (char is digit) output += capture[digit];
        else output += '%' + char;
    } else {
        output += char;
    }
}
I may implement this myself later.
Comment 1 Travis McHenry 2009-12-15 08:47:50 UTC
commit a54b8543fa24de3bf6fe6993724b588a9e48a1b4
Author: Travis McHenry <wordsizzle@gmail.com>
Date:   Tue Dec 15 00:44:23 2009 -0700

    Fix an autoreplace bug and enable escaping
    
    Make it so we can do multiple replaces in a single line again by
    not replacing the content of the 'global' replace variable
    BUG:211632
    
    Make it so we can support %# in replacements  without it getting
    lost in regex land by allowing escaping (with %%#).If you're so
    inclined please review the big comment explaining why we can't
    just not remove the leftover %# to make sure I'm not shooting hot
    air.
    BUG:218332

diff --git a/src/application.cpp b/src/application.cpp
index cf61af5..79c7730 100644
--- a/src/application.cpp
+++ b/src/application.cpp
@@ -1007,18 +1007,27 @@ QString Application::doAutoreplace(const QString& text,bool output)
                     {
                         // remember captured patterns
                         QStringList captures = needleReg.capturedTexts();
+                        QString replaceWith = replacement;
 
-                        // replace %0 - %9 in regex groups
+                        replaceWith.replace("%%","%\x01"); // escape double %
+                        // replace %0-9 in regex groups
                         for (int capture=0;capture<captures.count();capture++)
                         {
-                            replacement.replace(QString("%%1").arg(capture),captures[capture]);
+                            QString search = QString("%%1").arg(capture);
+                            replaceWith.replace(search, captures[capture]);
                         }
-                        replacement.remove(QRegExp("%[0-9]"));
+                        //Explanation why this is important so we don't forget:
+                        //If somebody has a regex that say has a replacement of url.com/%1/%2 and the
+                        //regex can either match one or two patterns, if the 2nd pattern match is left,
+                        //the url is invalid (url.com/match/%2). This is expected regex behavior I'd assume.
+                        replaceWith.remove(QRegExp("%[0-9]"));
+
+                        replaceWith.replace("%\x01","%"); // return escaped % to normal
                         // allow for var expansion in autoreplace
-                        replacement = Konversation::doVarExpansion(replacement);
+                        replaceWith = Konversation::doVarExpansion(replaceWith);
                         // replace input with replacement
-                        line.replace(index, captures[0].length(), replacement);
-                        index += replacement.length();
+                        line.replace(index, captures[0].length(), replaceWith);
+                        index += replaceWith.length();
                     }
                 } while (index >= 0 && index < (int)line.length());
             }