1# Strings and Bytes - Example for illustrative purposes only.
2
3import smartpy as sp
4
5
6@sp.module
7def main():
8 # A few helper functions that have probably no place in a real world
9 # smart contract but show general string manipulation techniques.
10
11 def string_split(params):
12 (s, sep) = params
13 prev_idx = 0
14 res = []
15 for idx in range(sp.len(s)):
16 if sp.slice(idx, 1, s).unwrap_some() == sep:
17 res.push(sp.slice(prev_idx, sp.as_nat(idx - prev_idx), s).unwrap_some())
18 prev_idx = idx + 1
19 if sp.len(s) > 0:
20 res.push(
21 sp.slice(prev_idx, sp.as_nat(sp.len(s) - prev_idx), s).unwrap_some()
22 )
23 return reversed(res)
24
25 def string_of_nat(params):
26 c = {
27 0: "0",
28 1: "1",
29 2: "2",
30 3: "3",
31 4: "4",
32 5: "5",
33 6: "6",
34 7: "7",
35 8: "8",
36 9: "9",
37 }
38 x = params
39 res = []
40 if x == 0:
41 res.push("0")
42 while 0 < x:
43 res.push(c[sp.mod(x, 10)])
44 x /= 10
45 return sp.concat(res)
46
47 def nat_of_string(params):
48 c = {
49 "0": 0,
50 "1": 1,
51 "2": 2,
52 "3": 3,
53 "4": 4,
54 "5": 5,
55 "6": 6,
56 "7": 7,
57 "8": 8,
58 "9": 9,
59 }
60 res = 0
61 for idx in range(sp.len(params)):
62 res = 10 * res + c[sp.slice(idx, 1, params).unwrap_some()]
63 return res
64
65 class MyContract(sp.Contract):
66 def __init__(self):
67 self.data.s0 = sp.Some("hello")
68 self.data.b0 = sp.Some(sp.bytes("0xAA"))
69 self.data.l0 = 0
70 self.data.l1 = 0
71 self.data.split = []
72 self.data.string_of_nat = ""
73 self.data.nat_of_string = 0
74
75 @sp.entrypoint
76 def concatenating(self, b0, b1, s, sb):
77 # Concatenating a list of strings or a list of bytes
78 self.data.s0 = sp.Some(sp.concat(s))
79 self.data.b0 = sp.Some(sp.concat([b0, b1, sp.concat(sb)]))
80
81 @sp.entrypoint
82 def concatenating2(self, b1, b2, s1, s2):
83 # Concatenating a two strings or two bytes
84 self.data.s0 = sp.Some(s1 + s2)
85 self.data.b0 = sp.Some(b1 + b2)
86
87 @sp.entrypoint
88 def slicing(self, b, s):
89 # Slicing a string or a byte (this returns an option)
90 self.data.s0 = sp.slice(2, 5, s)
91 self.data.b0 = sp.slice(1, 2, b)
92
93 # Computing length with sp.len
94 self.data.l0 = sp.len(s)
95 with sp.match(self.data.s0):
96 with sp.case.Some as arg:
97 self.data.l0 += sp.len(arg)
98 self.data.l1 = sp.len(b)
99
100 @sp.entrypoint
101 def test_split(self, params):
102 self.data.split = string_split((params, ","))
103
104 @sp.entrypoint
105 def test_string_of_nat(self, params):
106 self.data.string_of_nat = string_of_nat(params)
107
108 @sp.entrypoint
109 def test_nat_of_string(self, params):
110 self.data.nat_of_string = nat_of_string(params)
111
112
113# Tests
114@sp.add_test()
115def test():
116 scenario = sp.test_scenario("String Manipulations", main)
117 scenario.h1("String Manipulations")
118 c1 = main.MyContract()
119 scenario += c1
120
121 c1.slicing(s="012345678901234567890123456789", b=sp.bytes("0xAA00BBCC"))
122 scenario.verify_equal(c1.data.s0, sp.Some("23456"))
123 scenario.verify_equal(c1.data.b0, sp.Some(sp.bytes("0x00BB")))
124 scenario.verify_equal(c1.data.l0, 35)
125 scenario.verify_equal(c1.data.l1, 4)
126 c1.slicing(s="01", b=sp.bytes("0xCC"))
127 scenario.verify_equal(c1.data.s0, None)
128 # This one fails on sandbox because of missing type:
129 scenario.verify_equal(c1.data.b0, None)
130
131 c1.concatenating(
132 s=["01", "234", "567", "89"],
133 sb=[sp.bytes("0x1234"), sp.bytes("0x"), sp.bytes("0x4567aabbCCDD")],
134 b0=sp.bytes("0x11"),
135 b1=sp.bytes("0x223344"),
136 )
137 scenario.verify_equal(c1.data.s0, sp.Some("0123456789"))
138 scenario.verify_equal(c1.data.b0, sp.Some(sp.bytes("0x1122334412344567AABBCCDD")))
139
140 c1.concatenating2(s1="abc", s2="def", b1=sp.bytes("0xaaaa"), b2=sp.bytes("0xab"))
141
142 c1.test_split("abc,def,ghi,,j")
143
144 c1.test_string_of_nat(0)
145
146 scenario.verify_equal(c1.data.string_of_nat, "0")
147
148 c1.test_string_of_nat(12345678901234)
149
150 c1.test_nat_of_string("12312345678901234123")
151
152 scenario.show(c1.data)
153 scenario.verify_equal(
154 c1.data,
155 sp.record(
156 b0=sp.Some(sp.bytes("0xaaaaab")),
157 l0=2,
158 l1=1,
159 s0=sp.Some("abcdef"),
160 split=["abc", "def", "ghi", "", "j"],
161 string_of_nat="12345678901234",
162 nat_of_string=12312345678901234123,
163 ),
164 )