In .:
authorRaja R Harinath <harinath@hurrynot.org>
Fri, 20 May 2005 12:44:24 +0000 (12:44 -0000)
committerRaja R Harinath <harinath@hurrynot.org>
Fri, 20 May 2005 12:44:24 +0000 (12:44 -0000)
* System_test.dll.sources: Add
System.Text.RegularExpressions/RegexReplace.cs.

In System.Text.RegularExpressions:
Fix #74735.
* replace.cs (ReplacementEvaluator.Compile): Allow CompileTerm to
fail and yet have advanced the pointer.  Append the scanned-over
portion to the "literal" being built.
(ReplacementEvaluator.CompileTerm): Don't throw any exceptions.
If a term cannot be recognized, just return null.

In Test/System.Text.RegularExpressions:
* RegexReplace.cs: New file.  Most of the tests were inspired by
#74735.

svn path=/trunk/mcs/; revision=44813

mcs/class/System/ChangeLog
mcs/class/System/System.Text.RegularExpressions/ChangeLog
mcs/class/System/System.Text.RegularExpressions/replace.cs
mcs/class/System/System_test.dll.sources
mcs/class/System/Test/System.Text.RegularExpressions/ChangeLog
mcs/class/System/Test/System.Text.RegularExpressions/RegexReplace.cs [new file with mode: 0644]

index beb8d55ece8d5962b6bd3294e937ab9ca2154bc8..ca97aecd8ff2b91007126afe09be3552099eda4f 100644 (file)
@@ -1,5 +1,8 @@
 2005-05-20  Raja R Harinath  <rharinath@novell.com>
 
+       * System_test.dll.sources: Add
+       System.Text.RegularExpressions/RegexReplace.cs.
+
        * System.dll.sources: Update to reflect split-up of
        System.Text.RegularExpressions/match.cs.
 
index 852dfb4f27d8f4ab54af911f29c3ec9f05c103d8..28d4aa4e24f13ce70b3b00e47f09221b2407a8a0 100644 (file)
@@ -1,5 +1,12 @@
 2005-05-20  Raja R Harinath  <rharinath@novell.com>
 
+       Fix #74735.
+       * replace.cs (ReplacementEvaluator.Compile): Allow CompileTerm to
+       fail and yet have advanced the pointer.  Append the scanned-over
+       portion to the "literal" being built.
+       (ReplacementEvaluator.CompileTerm): Don't throw any exceptions.
+       If a term cannot be recognized, just return null.
+
        * compiler.cs (InterpreterFactory.GroupCount): Fix.  The 0'th
        index corresponds to Opcode.Info.
 
index b3fb72b2a58c8ffcdb860c12ec981f6d9d0febe7..5bb0b1f3296727bc8f16503b0b14fa0c8466b687 100644 (file)
@@ -67,22 +67,38 @@ namespace System.Text.RegularExpressions {
                        while (ptr < replacement.Length) {
                                c = replacement[ptr ++];
 
-                               if (c == '$') {
-                                       if (replacement[ptr] != '$') 
-                                               term = CompileTerm (replacement, ref ptr);
-                                       else
-                                               ++ ptr;
+                               if (c != '$') {
+                                       literal.Append (c);
+                                       continue;
+                               }
+
+                               // If the '$' was the last character, just emit it as is
+                               if (ptr == replacement.Length) {
+                                       literal.Append (c);
+                                       break;
                                }
 
+                               // If we saw a '$$'
+                               if (replacement[ptr] == '$') {
+                                       literal.Append (c);
+                                       ++ ptr;
+                                       continue;
+                               }
+
+                               int saveptr = ptr - 1;
+
+                               term = CompileTerm (replacement, ref ptr);
+
                                if (term != null) {
                                        term.Literal = literal.ToString ();
                                        terms.Add (term);
 
                                        term = null;
                                        literal.Length = 0;
+                               } else {
+                                       // If 'CompileTerm' couldn't identify it, don't abort, simply copy it over.
+                                       literal.Append (replacement, saveptr, ptr - saveptr);
                                }
-                               else
-                                       literal.Append (c);
                        }
 
                        if (term == null && literal.Length > 0) {
@@ -96,7 +112,7 @@ namespace System.Text.RegularExpressions {
                        if (Char.IsDigit (c)) {         // numbered group
                                int n = Parser.ParseDecimal (str, ref ptr);
                                if (n < 0 || n > regex.GroupCount)
-                                       throw new ArgumentException ("Bad group number.");
+                                       return null;
                                
                                return new Term (TermOp.Match, n);
                        }
@@ -105,14 +121,33 @@ namespace System.Text.RegularExpressions {
 
                        switch (c) {
                        case '{': {                     // named group
-                               string name = Parser.ParseName (str, ref ptr);
-                               if (str[ptr ++] != '}' || name == null)
-                                       throw new ArgumentException ("Bad group name.");
-                               
-                               int n = regex.GroupNumberFromName (name);
-                               
-                               if (n < 0)
-                                       throw new ArgumentException ("Bad group name.");
+                               string name;
+                               int n = -1;
+
+                               try {
+                                       // The parser is written such that there are few explicit range checks
+                                       // and depends on 'IndexOutOfRangeException' being thrown.
+
+                                       if (Char.IsDigit (str [ptr])) {
+                                               n = Parser.ParseDecimal (str, ref ptr);
+                                               name = "";
+                                       } else {
+                                               name = Parser.ParseName (str, ref ptr);
+                                       }
+                               } catch (IndexOutOfRangeException) {
+                                       ptr = str.Length;
+                                       return null;
+                               }
+
+                               if (ptr == str.Length || str[ptr] != '}' || name == null)
+                                       return null;
+                               ++ptr;                  // Swallow the '}'
+
+                               if (name != "")
+                                       n = regex.GroupNumberFromName (name);
+
+                               if (n < 0 || n > regex.GroupCount)
+                                       return null;
 
                                return new Term (TermOp.Match, n);
                        }
@@ -133,7 +168,7 @@ namespace System.Text.RegularExpressions {
                                return new Term (TermOp.All, 0);
 
                        default:
-                               throw new ArgumentException ("Bad replacement pattern.");
+                               return null;
                        }
                }
 
index 27e16d6666d099429defc336deb1c2170985920f..a566134f32693d7e7b3a689ac59ed2413538ff6a 100644 (file)
@@ -63,6 +63,7 @@ System.Text.RegularExpressions/PerlTrials.cs
 System.Text.RegularExpressions/RegexTrial.cs
 System.Text.RegularExpressions/RegexTest.cs
 System.Text.RegularExpressions/RegexBugs.cs
+System.Text.RegularExpressions/RegexReplace.cs
 System.Web/AspNetHostingPermissionAttributeTest.cs
 System.Web/AspNetHostingPermissionTest.cs
 System.IO.Compression/DeflateStreamCas.cs
index 4be7202eead9065db4806f92029bd98f1cab745f..2c679fabf3b54ca50341feb44887db06debbf863 100644 (file)
@@ -1,3 +1,8 @@
+2005-05-20  Raja R Harinath  <rharinath@novell.com>
+
+       * RegexReplace.cs: New file.  Most of the tests were inspired by
+       #74735.
+
 2005-04-20 Gonzalo Paniagua Javier <gonzalo@ximian.com>
 
        * PerlTest.cs: split.
diff --git a/mcs/class/System/Test/System.Text.RegularExpressions/RegexReplace.cs b/mcs/class/System/Test/System.Text.RegularExpressions/RegexReplace.cs
new file mode 100644 (file)
index 0000000..692fcd1
--- /dev/null
@@ -0,0 +1,83 @@
+//
+// RegexReplace.cs
+//
+// Author:
+//     Raja R Harinath <rharinath@novell.com>
+//
+// (C) 2005, Novell Inc.
+
+using System;
+using System.Text.RegularExpressions;
+
+using NUnit.Framework;
+
+namespace MonoTests.System.Text.RegularExpressions {
+
+       [TestFixture]
+       public class RegexReplaceTest {
+               struct testcase { 
+                       public string original, pattern, replacement, expected;
+                       public testcase (string o, string p, string r, string e)
+                       {
+                               original = o;
+                               pattern = p;
+                               replacement = r;
+                               expected = e;
+                       }
+               }
+               
+               static testcase [] tests = {
+                       //      original        pattern                 replacement             expected
+                       new testcase ("text",   "x",                    "y",                    "teyt"          ),
+                       new testcase ("text",   "x",                    "$",                    "te$t"          ),
+                       new testcase ("text",   "x",                    "$1",                   "te$1t"         ),
+                       new testcase ("text",   "x",                    "${1}",                 "te${1}t"       ),
+                       new testcase ("text",   "x",                    "$5",                   "te$5t"         ),
+                       new testcase ("te(x)t", "x",                    "$5",                   "te($5)t"       ),
+                       new testcase ("text",   "x",                    "${5",                  "te${5t"        ),
+                       new testcase ("text",   "x",                    "${foo",                "te${foot"      ),
+                       new testcase ("text",   "(x)",                  "$5",                   "te$5t"         ),
+                       new testcase ("text",   "(x)",                  "$1",                   "text"          ),
+                       new testcase ("text",   "e(x)",                 "$1",                   "txt"           ),
+                       new testcase ("text",   "e(x)",                 "$5",                   "t$5t"          ),
+                       new testcase ("text",   "e(x)",                 "$4",                   "t$4t"          ),
+                       new testcase ("text",   "e(x)",                 "$3",                   "t$3t"          ),
+                       new testcase ("text",   "e(x)",                 "${1}",                 "txt"           ),
+                       new testcase ("text",   "e(x)",                 "${3}",                 "t${3}t"        ),
+                       new testcase ("text",   "e(x)",                 "${1}${3}",             "tx${3}t"       ),
+                       new testcase ("text",   "e(x)",                 "${1}${name}",          "tx${name}t"    ),
+                       new testcase ("text",   "e(?<foo>x)",           "${1}${name}",          "tx${name}t"    ),
+                       new testcase ("text",   "e(?<foo>x)",           "${1}${foo}",           "txxt"          ),
+                       new testcase ("text",   "e(?<foo>x)",           "${goll}${foo}",        "t${goll}xt"    ),
+                       new testcase ("text",   "e(?<foo>x)",           "${goll${foo}",         "t${gollxt"     ),
+                       new testcase ("text",   "e(?<foo>x)",           "${goll${foo}}",        "t${gollx}t"    ),
+                       new testcase ("text",   "e(?<foo>x)",           "$${foo}}",             "t${foo}}t"     ),
+                       new testcase ("text",   "e(?<foo>x)",           "${${foo}}",            "t${x}t"        ),
+                       new testcase ("text",   "e(?<foo>x)",           "$${foo}}",             "t${foo}}t"     ),
+                       new testcase ("text",   "e(?<foo>x)",           "$${bfoo}}",            "t${bfoo}}t"    ),
+                       new testcase ("text",   "e(?<foo>x)",           "$${foo}}",             "t${foo}}t"     ),
+                       new testcase ("text",   "e(?<foo>x)",           "$${foo}",              "t${foo}t"      ),
+                       new testcase ("text",   "e(?<foo>x)",           "$$",                   "t$t"           ),
+                       new testcase ("text",   "(?<foo>e)(?<foo>x)",   "${foo}$1$2",           "txx$2t"        ),
+                       new testcase ("text",   "(e)(?<foo>x)",         "${foo}$1$2",           "txext"         ),
+                       new testcase ("text",   "(?<foo>e)(x)",         "${foo}$1$2",           "texet"         ),
+               };
+
+               [Test]
+               public void ReplaceTests ()
+               {
+                       string result;
+                       int i = 0;
+                       foreach (testcase test in tests) {
+                               try {
+                                       result = Regex.Replace (test.original, test.pattern, test.replacement);
+                                       Assert.AreEqual (result, test.expected, "rr#{0}: {1} ~ s,{2},{3},", i,
+                                                        test.original, test.pattern, test.replacement);
+                               } catch (Exception e) {
+                                       Assert.Fail ("rr#{0}: Exception thrown", i);
+                               }
+                               ++i;
+                       }
+               }
+       }
+}