Author: Carl Friedrich Bolz <[email protected]>
Branch:
Changeset: r64909:34888d691e22
Date: 2013-06-14 18:14 +0200
http://bitbucket.org/pypy/pypy/changeset/34888d691e22/
Log: an implementation of string_replace in rstring
diff --git a/rpython/rlib/rstring.py b/rpython/rlib/rstring.py
--- a/rpython/rlib/rstring.py
+++ b/rpython/rlib/rstring.py
@@ -82,6 +82,59 @@
res.reverse()
return res
+def string_replace(input, sub, by, maxsplit=-1):
+ if maxsplit == 0:
+ return input
+
+ if not sub:
+ upper = len(input)
+ if maxsplit > 0 and maxsplit < upper + 2:
+ upper = maxsplit - 1
+ assert upper >= 0
+
+ try:
+ result_size = ovfcheck(upper * len(by))
+ result_size = ovfcheck(result_size + upper)
+ result_size = ovfcheck(result_size + len(by))
+ remaining_size = len(input) - upper
+ result_size = ovfcheck(result_size + remaining_size)
+ except OverflowError:
+ raise
+ builder = StringBuilder(result_size)
+ for i in range(upper):
+ builder.append(by)
+ builder.append(input[i])
+ builder.append(by)
+ builder.append_slice(input, upper, len(input))
+ else:
+ # First compute the exact result size
+ count = input.count(sub)
+ if count > maxsplit and maxsplit > 0:
+ count = maxsplit
+ diff_len = len(by) - len(sub)
+ try:
+ result_size = ovfcheck(diff_len * count)
+ result_size = ovfcheck(result_size + len(input))
+ except OverflowError:
+ raise
+
+ builder = StringBuilder(result_size)
+ start = 0
+ sublen = len(sub)
+
+ while maxsplit != 0:
+ next = input.find(sub, start)
+ if next < 0:
+ break
+ builder.append_slice(input, start, next)
+ builder.append(by)
+ start = next + sublen
+ maxsplit -= 1 # NB. if it's already < 0, it stays < 0
+
+ builder.append_slice(input, start, len(input))
+
+ return builder.build()
+
# -------------- public API ---------------------------------
INIT_SIZE = 100 # XXX tweak
diff --git a/rpython/rlib/test/test_rstring.py
b/rpython/rlib/test/test_rstring.py
--- a/rpython/rlib/test/test_rstring.py
+++ b/rpython/rlib/test/test_rstring.py
@@ -1,6 +1,7 @@
import sys, py
from rpython.rlib.rstring import StringBuilder, UnicodeBuilder, split, rsplit
+from rpython.rlib.rstring import string_replace
from rpython.rtyper.test.tool import BaseRtypingTest, LLRtypeMixin
def test_split():
@@ -46,6 +47,39 @@
assert rsplit(u'endcase test', u'test') == [u'endcase ', u'']
py.test.raises(ValueError, rsplit, u"abc", u'')
+def test_string_replace():
+ assert string_replace('one!two!three!', '!', '@', 1) == 'one@two!three!'
+ assert string_replace('one!two!three!', '!', '') == 'onetwothree'
+ assert string_replace('one!two!three!', '!', '@', 2) == 'one@two@three!'
+ assert string_replace('one!two!three!', '!', '@', 3) == 'one@two@three@'
+ assert string_replace('one!two!three!', '!', '@', 4) == 'one@two@three@'
+ assert string_replace('one!two!three!', '!', '@', 0) == 'one!two!three!'
+ assert string_replace('one!two!three!', '!', '@') == 'one@two@three@'
+ assert string_replace('one!two!three!', 'x', '@') == 'one!two!three!'
+ assert string_replace('one!two!three!', 'x', '@', 2) == 'one!two!three!'
+ assert string_replace('abc', '', '-') == '-a-b-c-'
+ assert string_replace('abc', '', '-', 3) == '-a-b-c'
+ assert string_replace('abc', '', '-', 0) == 'abc'
+ assert string_replace('', '', '') == ''
+ assert string_replace('', '', 'a') == 'a'
+ assert string_replace('abc', 'ab', '--', 0) == 'abc'
+ assert string_replace('abc', 'xy', '--') == 'abc'
+ assert string_replace('123', '123', '') == ''
+ assert string_replace('123123', '123', '') == ''
+ assert string_replace('123x123', '123', '') == 'x'
+
+def test_string_replace_overflow():
+ if sys.maxint > 2**31-1:
+ py.test.skip("Wrong platform")
+ s = "a" * (2**16)
+ with py.test.raises(OverflowError):
+ string_replace(s, "", s)
+ with py.test.raises(OverflowError):
+ string_replace(s, "a", s)
+ with py.test.raises(OverflowError):
+ string_replace(s, "a", s, len(s) - 10)
+
+
def test_string_builder():
s = StringBuilder()
s.append("a")
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit