Skip to content

Commit 3e6ddc6

Browse files
Kishan-Vedubaidsk
andauthored
Added str.replace() (#2587)
* added str.replace() string API * references updated * Delete kishan.py * updated references 2 * removed empty string tests * fix c test * fixed empty string case * updated references 3 * TEST: Update reference tests --------- Co-authored-by: Shaikh Ubaid <[email protected]>
1 parent db6ed14 commit 3e6ddc6

File tree

62 files changed

+1348
-1229
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1348
-1229
lines changed

integration_tests/test_str_01.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,55 @@ def test_str_split():
114114
assert res5 == ["123"]
115115
# assert res6 == [""]
116116

117+
def test_str_replace():
118+
x: str = "abc"
119+
a: str = "zzaaabracadabra"
120+
print(a.replace("a",""))
121+
print(a.replace("",""))
122+
print(a.replace("a","b"))
123+
print(a.replace("e","a"))
124+
print(a.replace("ab","ba"))
125+
print(a.replace("c","z"))
126+
print(a.replace("zza","yo"))
127+
print(a.replace("a","b",0))
128+
print(a.replace("a","b",1))
129+
print(a.replace("a","b",2))
130+
print(a.replace("a","b",2))
131+
print(a.replace("a","b",3))
132+
print(a.replace("a","b",4))
133+
print(a.replace("a","b",5))
134+
print(a.replace("a","b",6))
135+
print(a.replace("a","b",7))
136+
print(a.replace("a","b",8))
137+
print(a.replace("a","b",9))
138+
print(a.replace("b","k",1))
139+
print(a.replace("b","k",2))
140+
print(a.replace("zza","yo",2))
141+
print(x.replace("", ","))
142+
assert a.replace("a","") == "zzbrcdbr"
143+
assert a.replace("","") == "zzaaabracadabra"
144+
assert a.replace("a","b") == "zzbbbbrbcbdbbrb"
145+
assert a.replace("e","a") == "zzaaabracadabra"
146+
assert a.replace("ab","ba") == "zzaabaracadbara"
147+
assert a.replace("c","z") == "zzaaabrazadabra"
148+
assert a.replace("zza","yo") == "yoaabracadabra"
149+
assert a.replace("a","b",0) == "zzaaabracadabra"
150+
assert a.replace("a","b",1) == "zzbaabracadabra"
151+
assert a.replace("a","b",2) == "zzbbabracadabra"
152+
assert a.replace("a","b",2) == "zzbbabracadabra"
153+
assert a.replace("a","b",3) == "zzbbbbracadabra"
154+
assert a.replace("a","b",4) == "zzbbbbrbcadabra"
155+
assert a.replace("a","b",5) == "zzbbbbrbcbdabra"
156+
assert a.replace("a","b",6) == "zzbbbbrbcbdbbra"
157+
assert a.replace("a","b",7) == "zzbbbbrbcbdbbrb"
158+
assert a.replace("a","b",8) == "zzbbbbrbcbdbbrb"
159+
assert a.replace("a","b",9) == "zzbbbbrbcbdbbrb"
160+
assert a.replace("b","k",1) == "zzaaakracadabra"
161+
assert a.replace("b","k",2) == "zzaaakracadakra"
162+
assert a.replace("zza","yo",2) == "yoaabracadabra"
163+
assert x.replace("", ",") == ",a,b,c,"
164+
165+
117166
def check():
118167
f()
119168
test_str_concat()
@@ -127,5 +176,6 @@ def check():
127176
test_constant_str_subscript()
128177
test_str_title()
129178
test_str_split()
179+
test_str_replace()
130180

131181
check()

src/lpython/semantics/python_ast_to_asr.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6789,6 +6789,41 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
67896789
} else {
67906790
fn_args.push_back(al, str);
67916791
}
6792+
} else if(attr_name == "replace") {
6793+
if(!(args.size() == 2 || args.size()==3)) {
6794+
throw SemanticError("str.replace() takes two or three arguments.", loc);
6795+
}
6796+
ASR::expr_t *arg_value = args[0].m_value;
6797+
ASR::ttype_t *arg_value_type = ASRUtils::expr_type(arg_value);
6798+
if (!ASRUtils::is_character(*arg_value_type)) {
6799+
throw SemanticError("str.replace() argument 1 must be str", loc);
6800+
}
6801+
arg_value = args[1].m_value;
6802+
arg_value_type = ASRUtils::expr_type(arg_value);
6803+
if (!ASRUtils::is_character(*arg_value_type)) {
6804+
throw SemanticError("str.replace() argument 2 must be str", loc);
6805+
}
6806+
fn_call_name = "_lpython_str_replace";
6807+
ASR::call_arg_t str;
6808+
str.loc = loc;
6809+
str.m_value = s_var;
6810+
6811+
ASR::call_arg_t value;
6812+
value.loc = loc;
6813+
value.m_value = args[0].m_value;
6814+
fn_args.push_back(al, str);
6815+
fn_args.push_back(al, value);
6816+
value.m_value = args[1].m_value;
6817+
fn_args.push_back(al, value);
6818+
if(args.size()==3){
6819+
ASR::expr_t *arg_value = args[2].m_value;
6820+
ASR::ttype_t *arg_value_type = ASRUtils::expr_type(arg_value);
6821+
if (!ASRUtils::is_integer(*arg_value_type)) {
6822+
throw SemanticError("str.replace() argument 3 must be int", loc);
6823+
}
6824+
value.m_value = args[2].m_value;
6825+
fn_args.push_back(al, value);
6826+
}
67926827
} else if(attr_name.size() > 2 && attr_name[0] == 'i' && attr_name[1] == 's') {
67936828
/*
67946829
String Validation Methods i.e all "is" based functions are handled here

src/lpython/semantics/python_comptime_eval.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ struct PythonIntrinsicProcedures {
9191
{"_lpython_str_lstrip", {m_builtin, &not_implemented}},
9292
{"_lpython_str_strip", {m_builtin, &not_implemented}},
9393
{"_lpython_str_split", {m_builtin, &not_implemented}},
94+
{"_lpython_str_replace", {m_builtin, &not_implemented}},
9495
{"_lpython_str_swapcase", {m_builtin, &not_implemented}},
9596
{"_lpython_str_startswith", {m_builtin, &not_implemented}},
9697
{"_lpython_str_endswith", {m_builtin, &not_implemented}},

src/runtime/lpython_builtin.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,39 @@ def _lpython_str_split(x: str, sep:str) -> list[str]:
915915
start += ind + len(sep)
916916
return res
917917

918+
@overload
919+
def _lpython_str_replace(x: str, old:str, new:str) -> str:
920+
return _lpython_str_replace(x, old, new, len(x))
921+
922+
923+
@overload
924+
def _lpython_str_replace(x: str, old:str, new:str, count: i32) -> str:
925+
if (old == ""):
926+
res1: str = ""
927+
s: str
928+
for s in x:
929+
res1 += new + s
930+
return res1 + new
931+
res: str = ""
932+
i: i32 = 0
933+
ind: i32 = -1
934+
l: i32 = len(new)
935+
lo: i32 = len(old)
936+
lx: i32 = len(x)
937+
c: i32 = 0
938+
t: i32 = -1
939+
940+
while(c<count):
941+
t = _lpython_str_find(x[i:lx], old)
942+
if(t==-1):
943+
break
944+
ind = i + t
945+
res = res + x[i:ind] + new
946+
i = ind + lo
947+
c = c + 1
948+
res = res + x[i:lx]
949+
return res
950+
918951
@overload
919952
def _lpython_str_swapcase(s: str) -> str:
920953
res :str = ""

tests/reference/asr-array_01_decl-39cf894.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"outfile": null,
77
"outfile_hash": null,
88
"stdout": "asr-array_01_decl-39cf894.stdout",
9-
"stdout_hash": "7e3c68aa6acba27674e544f894bb141357db82f8840c756af448f5bb",
9+
"stdout_hash": "f14010ffcf7d42b89e54c88ebecc7ca51d67b204825e07f4f708875e",
1010
"stderr": null,
1111
"stderr_hash": null,
1212
"returncode": 0

0 commit comments

Comments
 (0)