Skip to content

String Operations in Solidity

This example demonstrates different ways to work with strings in Solidity, including concatenation, comparison, and encoding.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract StringOperations {
    // State variables
    string public storedString = "Hello";

    // String comparison using keccak256 hash
    function compareStrings(string memory str1, string memory str2) public pure returns (bool) {
        return keccak256(abi.encodePacked(str1)) == keccak256(abi.encodePacked(str2));
    }

    // String concatenation using string.concat (Solidity 0.8.12+)
    function concatenateStrings(string memory str1, string memory str2) public pure returns (string memory) {
        return string.concat(str1, str2);
    }

    // Multiple string concatenation with a number using string.concat
    function concatenateWithNumber(string memory str1, uint256 number, string memory str2) public pure returns (string memory) {
        return string.concat(str1, " ", toString(number), " ", str2);
    }

    // Legacy concatenation using abi.encodePacked
    function concatenateStringsLegacy(string memory str1, string memory str2) public pure returns (string memory) {
        return string(abi.encodePacked(str1, str2));
    }

    // Convert uint to string using OpenZeppelin's approach
    function toString(uint256 value) internal pure returns (string memory) {
        // Special case for 0
        if (value == 0) {
            return "0";
        }

        // Get number of digits
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }

        // Create bytes array
        bytes memory buffer = new bytes(digits);

        // Fill buffer from right to left
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }

        return string(buffer);
    }

    // Demonstrate different encoding methods
    function demonstrateEncoding(string memory str1, string memory str2) public pure returns (bytes memory, bytes memory, bytes memory) {
        // abi.encode: Pads data to 32 bytes
        bytes memory encoded = abi.encode(str1, str2);

        // abi.encodePacked: Minimal encoding without padding
        bytes memory encodedPacked = abi.encodePacked(str1, str2);

        // keccak256: Creates a hash of the data
        bytes memory hashed = abi.encodePacked(keccak256(abi.encodePacked(str1, str2)));

        return (encoded, encodedPacked, hashed);
    }

    // Get string length (UTF-8 bytes length)
    function getStringLength(string memory str) public pure returns (uint256) {
        return bytes(str).length;
    }
}

Key Concepts

  1. String Comparison

    • Strings can't be directly compared
    • Must use keccak256 hash comparison
    • Case-sensitive comparison
  2. String Concatenation

    • Use abi.encodePacked() for efficient concatenation
    • Convert result back to string
    • Can combine strings with other types
  3. Encoding Methods

    • abi.encode(): Pads each element to 32 bytes
    • abi.encodePacked(): Minimal encoding without padding
    • keccak256(): Creates a 32-byte hash
  4. String Length

    • Returns bytes length (UTF-8 encoded)
    • Not character count for non-ASCII strings
    • Gas efficient operation

Best Practices

  1. Use abi.encodePacked() for efficient string operations
  2. Cache string operations to save gas
  3. Be aware of UTF-8 encoding when working with strings
  4. Consider gas costs when manipulating strings
  5. Use events to log string changes

Common Use Cases

  1. String Comparison

    • User input validation
    • State verification
    • Access control
  2. String Concatenation

    • Building messages
    • Creating URIs
    • Formatting output
  3. Encoding

    • Creating unique identifiers
    • Hashing data
    • Signature verification
  4. String Length

    • Input validation
    • Data size verification
    • Gas estimation