diff options
author | Steve Newman <devnull@localhost> | 2009-06-18 17:55:47 -0700 |
---|---|---|
committer | Steve Newman <devnull@localhost> | 2009-06-18 17:55:47 -0700 |
commit | 927345d326f076201b77d327e569e8a66d1c023b (patch) | |
tree | e1d1a415d48657f32a4a9af5f7310098e7c1f275 /src/pkg/regexp/regexp.go | |
parent | 12dbf4c179d004c18f94dd5777fa81e503cf1eab (diff) | |
download | golang-927345d326f076201b77d327e569e8a66d1c023b.tar.gz |
Add a ReplaceAll method to Regexp.
APPROVED=r,rsc
DELTA=189 (187 added, 0 deleted, 2 changed)
OCL=30205
CL=30517
Diffstat (limited to 'src/pkg/regexp/regexp.go')
-rw-r--r-- | src/pkg/regexp/regexp.go | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go index b79800dd9..5fb606a27 100644 --- a/src/pkg/regexp/regexp.go +++ b/src/pkg/regexp/regexp.go @@ -24,6 +24,7 @@ package regexp import ( "container/vector"; + "io"; "os"; "runtime"; "utf8"; @@ -282,7 +283,7 @@ func (p *parser) regexp() (start, end instr) var iNULL instr func special(c int) bool { - s := `\.+*?()|[]`; + s := `\.+*?()|[]^$`; for i := 0; i < len(s); i++ { if c == int(s[i]) { return true @@ -762,3 +763,67 @@ func Match(pattern string, s string) (matched bool, error os.Error) { } return re.Match(s), nil } + +// ReplaceAll returns a copy of src in which all matches for the Regexp +// have been replaced by repl. No support is provided for expressions +// (e.g. \1 or $1) in the replacement string. +func (re *Regexp) ReplaceAll(src, repl string) string { + lastMatchEnd := 0; // end position of the most recent match + searchPos := 0; // position where we next look for a match + buf := new(io.ByteBuffer); + for searchPos <= len(src) { + a := re.doExecute(src, searchPos); + if len(a) == 0 { + break; // no more matches + } + + // Copy the unmatched characters before this match. + io.WriteString(buf, src[lastMatchEnd:a[0]]); + + // Now insert a copy of the replacement string, but not for a + // match of the empty string immediately after another match. + // (Otherwise, we get double replacement for patterns that + // match both empty and nonempty strings.) + if a[1] > lastMatchEnd || a[0] == 0 { + io.WriteString(buf, repl); + } + lastMatchEnd = a[1]; + + // Advance past this match; always advance at least one character. + rune, width := utf8.DecodeRuneInString(src[searchPos:len(src)]); + if searchPos + width > a[1] { + searchPos += width; + } else if searchPos + 1 > a[1] { + // This clause is only needed at the end of the input + // string. In that case, DecodeRuneInString returns width=0. + searchPos++; + } else { + searchPos = a[1]; + } + } + + // Copy the unmatched characters after the last match. + io.WriteString(buf, src[lastMatchEnd:len(src)]); + + return string(buf.Data()); +} + +// QuoteMeta returns a string that quotes all regular expression metacharacters +// inside the argument text; the returned string is a regular expression matching +// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`. +func QuoteMeta(s string) string { + b := make([]byte, 2 * len(s)); + + // A byte loop is correct because all metacharacters are ASCII. + j := 0; + for i := 0; i < len(s); i++ { + if special(int(s[i])) { + b[j] = '\\'; + j++; + } + b[j] = s[i]; + j++; + } + return string(b[0:j]); +} + |