Master String Manipulation in Solidity
Tags: web3, blockchain, solidity, tutorial
Published: 2022-05-15 20:17:33

# **Introduction**

String manipulation in Solidity is not as straightforward as it is in most other programming languages, like JavaScript, Python, Java, etc.; with the entire notion/belief that a good background in JavaScript gives you an edge in Solidity, it sucks and becomes frustrating when you can't just use the (+) sign to concatenate strings in Solidity, like ("a"+"b") or do other simple string manipulations the way we are used to in most other programming languages. 

## What is string in programming?

String is a piece of text or an array/sequence/collection of alphanumeric characters enclosed within a single or double quote mark, such as 'Welcome!' or "number 3". It is one of the essential concepts in computer programming.

String is a data type used in most computer languages to store data values of ordered sequences of characters. It can be saved in a variable, entered by the user (input), or displayed on the screen (output). 

Manipulation of string to deliver information or change its contents is usually possible and relatively simple. The following are some of the things we can do with string:

- Check length of a string
- Check character position in a string
- Concatenate(join strings to form another word) strings
- Compare if two strings are the same
- Change letters in a string from uppercase to lowercase and verse versa
- Reverse a string

## String in solidity

String in Solidity has some similarities with bytes; both are dynamic array types, which means they can hold data of any size. Each element of a bytes variable is a single byte, whereas each element of a string variable is a string character. it does not support functions to:

- Get string length
- Concatenate strings 
- Convert from upper case to lower case 
- Join two strings 
- Reverse string
- Compare two strings 
- To achieve any of the above mentioned, you have to do some sorts of manual manipulations.

In Solidity, string is an array of UTF-8 characters that can be converted to bytes easily, and this is the primary way of manipulating string. It's vital to note that UTF-8 characters don't always match bytes perfectly. Although the conversion will be accurate in either direction, there is no direct relationship between each byte index and the associated string index. It's also worth remembering that string literals are limited to readable ASCII characters.


## Project setup

Go to [Remix IDE](https://remix.ethereum.org/), in your workspace create a new file called **stringMan.sol.**
Go to your workspace compiler, set the compiler to the latest local version or any version greater than or equal to 0.8.0, and enable the auto compiler so that your work compiles automatically on the go, this will allow you to spot an error easily, that's one great thing I really love about Remix IDE.
Now, open the **stringMan.sol** file and set the `SPDX-Licence-Identifier: UNLICENSED` and `Pragma solidity ^0.8.0.0;`. Awesome! Our environment is all set. 


![](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682263043511_set.png)




## Find the length of a string

Now that we have successfully set up our project environment, let’s start getting our hands dirty!
In your **stringMan.sol** file, create a contract called **StringManipulation,** inside the StringManipulation contract, create a **string** called **str1,** then set **str1** to the string literal "Congratulations".


    // SPDX-License-Identifier: UNLICENSED;
    pragma solidity ^0.8.0.0;
    
    contract StringManipulation{
        string public str1 = "Congratulations";
    }

Moving on, let’s create a function that gets the value of our string variable  **str1,**  a function that gets the length of the string, and a function that sets the value of **str1** to a new string.

First, declare a function called **getStr** that returns the string **str1,** then declare another function called **getStrLength** that returns the length of the string, and declare another function called **setStr** that sets the string “**str1**” to a new string of your choice.


    // SPDX-License-Identifier: UNLICENSED;
    pragma solidity ^0.8.0.0;
    
    contract StringManipulation {
        //create string
        string public str1 = "Congratulations";
    
       //get string function
        function getStr() public view returns(string memory) {
            return str1;
        }
    
        //get string length function
        function getStrLength() public view returns(uint) {
            bytes memory strB = bytes(str1);
            return strB.length;
        }
    
        //set string function
        function setStr(string memory str) public {
            str1 = str;
        }
    }

In the above code, the first function i.e the **get string function** will return the value of the string variable “**str1**” which is **congratulations**, for the second function i.e the **get string length function**, since we cannot get the length of a string directly, we converted the string **str1** to byte and return the length, and for the last function which is the **set string function**, we set the string variable **str1** to a new string variable **str** which allows us to set the string **str1** to any string of our choice.


## Concatenate strings

Now that we know how to find our way around getting the length of a string, let’s move on to string concatenation. 
In your StringManipulation contract, create another function called **concateString,** let it take 2 arguments **str1** and **str2**, and return the concatenated string.


    // SPDX-License-Identifier: UNLICENSED;
    pragma solidity ^0.8.0.0;
    
    contract StringManipulation{
        string public str1 = "Congratulations";
       
    //get string function
        function getStr() public view returns(string memory) {
            return str1;
        }
    
        //set string function
        function setStr(string memory str) public {
            str1 = str;
        }
    
        //get string length function
        function getStrLength() public view returns(uint) {
            bytes memory strB = bytes(str1);
            return strB.length;
        }
    
    
        //concatenate strings function
        function concatString(
            string memory _str1, 
            string memory _str2
            ) public pure returns(string memory) {
        return string (abi.encodePacked(_str1,_str2));
        }
    }

In solidity, you cannot concatenate strings simply by using the plus sign like in JavaScript and some other languages, e.g. (str1 + str2), instead, you call the abi.encodedPacked() function and passed in the strings to be concatenated.


## Compare strings

With string concatenation successfully out of the way, you should drink a glass of juice and take a deep breath. having done that, let’s keep on moving…
Head over to your **StringManipulation** contract again, create another function called **compareStr**, let it take two(2) string arguments **str1** and **str2** and return a boolean.

    // SPDX-License-Identifier: UNLICENSED;
    pragma solidity ^0.8.0.0;
    
    contract StringManipulation{
        string public str1 = "Congratulations";
    
       //get string function
        function getStr() public view returns(string memory) {
            return str1;
        }
    
        //set string function
        function setStr(string memory str) public {
            str1 = str;
        }
    
        //get string length function
        function getStrLength() public view returns(uint) {
            bytes memory strB = bytes(str1);
            return strB.length;
        }
    
        //concatenate strings function
        function concatString(
            string memory _str1, 
            string memory _str2
            ) public pure returns(string memory) {
        return string (abi.encodePacked(_str1,_str2));
        }
    
        //compare strings function
        function compare(
            string memory _str1, 
            string memory _str2
            ) external pure returns(bool){
                return keccak256(abi.encodePacked(_str1)
                ) == keccak256(abi.encodePacked(_str2));
                }
    }
    

Just as in concatenation, to compare 2 strings in solidity, we called the keccak256 function and passed in the abi.encoded function which takes the argument, and then compares.


## Reverse string

I am sure you are feeling like a boss already, you should be because it’s not easy getting here. Without any delay, let’s see how we can reverse a string.
Still, inside your **StringManipulation** smart contract, create a function called **reverseStr** that takes a string argument **_str** and returns a string(reversed of the string that was passed in)

    // SPDX-License-Identifier: UNLICENSED;
    pragma solidity ^0.8.0.0;
    
    contract StringManipulation{
        string public str1 = "Congratulations";
    
       //get string function
        function getStr() public view returns(string memory) {
            return str1;
        }
    
        //set string function
        function setStr(string memory str) public {
            str1 = str;
        }
    
        //get string length function
        function getStrLength() public view returns(uint) {
            bytes memory strB = bytes(str1);
            return strB.length;
        }
    
        //concatenate strings function
        function concatString(
            string memory _str1, 
            string memory _str2
            ) public pure returns(string memory) {
        return string (abi.encodePacked(_str1,_str2));
        }
    
        //compare strings function
        function compareStr(
            string memory _str1, 
            string memory _str2
            ) external pure returns(bool){
                return keccak256(abi.encodePacked(_str1)
                ) == keccak256(abi.encodePacked(_str2));
                }
    
           //reverse string function
        function reverseStr(string memory _str) external pure returns(string memory){
            bytes memory baseByte = bytes(_str);
            string memory tempValue = new string(baseByte.length);
            bytes memory reverse = bytes(tempValue); 
            for(uint i = 0; i < baseByte.length; i++) {
                 reverse[baseByte.length - i - 1] = baseByte[i];
                 }
                 return string(reverse);
                 }
    }

Here, we converted the string to byte, get the instance of the string length, and simply looped through from the back.


## Convert string to lower case

Moving further, let’s see how we can convert a string from uppercase to lowercase. In your **StringManipulation** contract, create a function called **toLowerCase** that takes a string argument **_str** and returns a string(the lowercase of the passed in string)

    // SPDX-License-Identifier: UNLICENSED;
    pragma solidity ^0.8.0.0;
    
    contract StringManipulation{
        string public str1 = "Congratulations";
    
       //get string function
        function getStr() public view returns(string memory) {
            return str1;
        }
    
        //set string function
        function setStr(string memory str) public {
            str1 = str;
        }
    
        //get string length function
        function getStrLength() public view returns(uint) {
            bytes memory strB = bytes(str1);
            return strB.length;
        }
    
        //concatenate strings function
        function concatString(
            string memory _str1, 
            string memory _str2
            ) public pure returns(string memory) {
        return string (abi.encodePacked(_str1,_str2));
        }
    
        //compare strings function
        function compareStr(
            string memory _str1, 
            string memory _str2
            ) external pure returns(bool){
                return keccak256(abi.encodePacked(_str1)
                ) == keccak256(abi.encodePacked(_str2));
                }
    
           //reverse string function
        function reverseStr(string memory _str) external pure returns(string memory){
            bytes memory baseByte = bytes(_str);
            string memory tempValue = new string(baseByte.length);
            bytes memory reverse = bytes(tempValue); 
            for(uint i = 0; i < baseByte.length; i++) {
                 reverse[baseByte.length - i - 1] = baseByte[i];
                 }
                 return string(reverse);
                 } 
    
        //convert string to lowercase
        function toLowerCase(string memory _str) public pure returns (string memory) {
            bytes memory bString = bytes(_str);
            bytes memory bLowerCase = new bytes(bString.length);
            for (uint j = 0; j < bString.length; j++) {
                // Uppercase character...
                if ((uint8(bString[j]) >= 65) && (uint8(bString[j]) <= 90)) {
                    // So we add 32 to make it lowercase
                    bLowerCase[j] = bytes1(uint8(bString[j]) + 32);
                } else {
                    bLowerCase[j] = bString[j];
                }
            }
            return string(bLowerCase);
        }
    }

For the **toLowerCase** function, we first converted the string to byte, then get the instance of the length; since the ASCII values of `A - Z` are from `65 - 90`, and that of `a - z`, from `97 - 112`, we looped through to check if each character is within the range of `65 - 90(A - Z)`, add 32 if found to be true, to convert it to a lower case else return it that way.


## Test functions

If everything went well, your smart contract should be successfully compiled by now since it’s in auto compile. If you didn’t enable auto compile, now is the time to compile your smart contract, hit the compile button to compile it, and head over to deploy once compiled. 


![](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682262730781_deploy.png)


Now that you have successfully deployed your smart contract, let’s test all the functions to ensure they are working as they should:

**Get string, set string and get string length functions:**

![](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682258946390_get3.png)

![Get string and get string length](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682258973193_get1.png)

![Set string, get string and get string length](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682258993512_get2.png)


**Concatenate strings function:**

![](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682258835003_concate2.png)

![](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682258855402_concat1.png)


**Compare strings function:**
![](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682258646400_compare3.png)

![It returns true if the words are the same](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682258690724_compare1.png)



![it returns false if the two(2) words are different](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682258721245_compare2.png)


**Reverse string function:**
![](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682257761123_reverse2.png)

![](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682257875698_reverse1.png)


**toLowerCase function:**


![](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682259344032_lowercase2.png)

![](https://paper-attachments.dropboxusercontent.com/s_E5157F8A5E63F9FAA7ED8C99D44B5138C3B736F508C947E5B288014315DA4CD3_1682259373539_lowercase1.png)




## Conclusion:

It is not very efficient to manipulate strings in solidity, hence it is not recommended. Using strings in solidity is quite expensive since it consumes too much gas thereby costing too much gas fee; if you can, avoid string manipulation and attempt to replace it with byte instead. 

Also, Stings in Solidity accepts the backslash character ( \ ) as an escape character and the backslash plus n characters (\ + n)  (\n) as a new line character, just like JavaScript.


## Reference

[Solidity 0. 8. 13 Documentation](https://docs.soliditylang.org/en/latest/types.html?highlight=string#string-literals-and-types)
[Etheruem/Solidity toLower() equivalent](https://gist.github.com/ottodevs/c43d0a8b4b891ac2da675f825b1d1dbf)
[String manipulation in Solidity](https://youtu.be/gNlwpr3vGYM)

**Get the complete code** [**here**](https://github.com/Augusta-E/string-manipulation-sol/blob/e371cc524b0e9f9c206ed0ef31f56c1a2388d1f6/stringMan.sol)

**Let's connect:**
[Linkedin](https://www.linkedin.com/in/augusta-e/)
[Twitter](https://twitter.com/EhiheboloA)