Working with strings in Solidity is not as easy as working with strings in other high-level programming languages, such as JavaScript, Python, and so on. Therefore, many Solidity programmers have come up with various libraries and contracts to make it easy to work with strings.
The strings library is the most popular strings utility library. It lets us join, concatenate, split, compare, and so on by converting a string to something called a slice. A slice is a struct that holds the length of the string and the address of the string. Since a slice only has to specify an offset and a length, copying and manipulating slices is a lot less expensive than copying and manipulating the strings they reference.
To further reduce gas costs, most functions on slice that need to return a slice modify the original one instead of allocating a new one; for instance, s.split(".") will return the text up to the first ".", modifying s to only contain the remainder of the string after the ".". In situations where you do not want to modify the original slice, you can make a copy with .copy(), for example, s.copy().split("."). Try and avoid using this idiom in loops; since Solidity has no memory management, it will result in allocating many short-lived slices that are later discarded.
Functions that have to copy string data will return strings rather than slices; these can be cast back to slices for further processing if required.
Let's look at a few examples of working with strings using the strings library:
pragma Solidity ^0.4.0;
import "github.com/Arachnid/Solidity-stringutils/strings.sol";
contract Contract
{
using strings for *;
function Contract()
{
//convert string to slice
var slice = "xyz abc".toSlice();
//length of string
var length = slice.len();
//split a string
//subslice = xyz
//slice = abc
var subslice = slice.split(" ".toSlice());
//split a string into an array
var s = "www.google.com".toSlice();
var delim = ".".toSlice();
var parts = new string[](s.count(delim));
for(uint i = 0; i < parts.length; i++) {
parts[i] = s.split(delim).toString();
}
//Converting a slice back to a string
var myString = slice.toString();
//Concatenating strings
var finalSlice = subslice.concat(slice);
//check if two strings are equal
if(slice.equals(subslice))
{
}
}
}
The preceding code is self-explanatory.
Functions that return two slices come in two versions: a nonallocating version that takes the second slice as an argument, modifying it in place, and an allocating version that allocates and returns the second slice; for example, let's take a look at the following:
var slice1 = "abc".toSlice();
//moves the string pointer of slice1 to point to the next rune (letter)
//and returns a slice containing only the first rune
var slice2 = slice1.nextRune();
var slice3 = "abc".toSlice();
var slice4 = "".toSlice();
//Extracts the first rune from slice3 into slice4, advancing the slice to point to the next rune and returns slice4.
var slice5 = slice3.nextRune(slice4);