templates.stringManipulations

  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    )