Skip to content

How To Compare Strings in Solidity — A Comprehensive Guide

How To Compare Strings in Solidity — A Comprehensive Guide - cover image

Comparing strings in Solidity can be a bit tricky due to the unique characteristics of how strings are stored and manipulated on the Ethereum Virtual Machine (EVM). Unlike other programming languages where strings are compared using simple equality operators like “==”, Solidity requires a more nuanced approach due to its limited support for string manipulation.

Strings in Solidity

The main use case of strings in Solidity is to handle the textual data in smart contracts. Because of the limitations of the Ethereum Virtual Machine (EVM), strings in Solidity have certain limitations compared to many other programming languages. In Solidity, strings are basically byte arrays, or arrays of bytes. Because it compares memory addresses rather than the actual contents of the string, direct comparison using equality operators does not produce the intended result.

As a blockchain developer or someone starting out with learning Solidity, it is important to understand the key features of the different types of variables—our focus for today is strings in Solidity.

Key Properties

  • Reference Type: Strings in Solidity actually store the location of the data rather than the data itself. They point (or reference) to the starting position of the data in the storage.
  • Lack of Native String Manipulation Functions: Solidity does not provide built-in functions for common string operations such as concatenation, slicing, or comparison. Developers must implement these functionalities manually, often leading to more complex code.
  • Immutability: Once a value is assigned to a string, its value cannot be changed directly. To modify a string, a new string must be created with the desired changes.
  • Memory and Storage Considerations: Strings can be stored in memory or storage, each with different gas costs and persistence characteristics. Understanding the distinction between memory (temporary) and storage (permanent) is essential for efficient smart contract development.

Different Methods of Comparing Strings in Solidity

There are several methods that can be used to compare strings in Solidity. Let’s discuss each method in detail:

1. Hash Comparison

This method involves hashing the strings using a cryptographic hash function like SHA-256 and then comparing the resulting hash values. If the hashes match, the strings are considered equal.

function compareStrings(string memory _a, string memory _b) public pure returns(bool) {
    return keccak256(abi.encodePacked(_a)) == keccak256(abi.encodePacked(_b));
}

This function compares two strings by hashing them using the keccak256 cryptographic hash function and checking if the hash values are equal, returning a boolean indicating the comparison result.

🔥 Check this course out: Build a One Piece Personality dApp With Solidity

2. Length and Character Comparison

Iterate over each character of the strings and compare them sequentially. Additionally, compare the lengths of the strings to ensure they have the same length before performing character-wise comparisons to avoid out-of-bounds errors.

function compareStrings(string memory _a, string memory _b) public pure returns(bool) {
    if (bytes(_a).length != bytes(_b).length) {
        return false;
    }

    for (uint i = 0; i < bytes(_a).length; i++) {
        if (bytes(_a)[i] != bytes(_b)[i]) {
            return false;
        }
    }

    return true;
}

The function compareStrings compares two strings character by character and returns false if they have different lengths or if any corresponding characters are not equal. If the lengths of the strings match and all characters at corresponding positions are equal, the function returns true, indicating that the strings are identical.

    3. Using Libraries

    You can create a library with functions for string comparison and reuse it across multiple contracts. This promotes code reusability and simplifies maintenance.

    library StringUtils {
        function compareStrings(string memory _a, string memory _b) internal pure returns(bool) {
            return keccak256(abi.encodePacked(_a)) == keccak256(abi.encodePacked(_b));
        }
    }
    
    contract StringComparison {
        using StringUtils for string;
    
        function compare(string memory _a, string memory _b) public pure returns(bool) {
            return _a.compareStrings(_b);
        }
    }

    The function compareStrings(string memory _a, string memory _b) internal pure returns(bool): This function in the StringUtils library compares two strings by hashing them and checking for equality. The StringComparison contract enables the StringUtils library for all string types in the contract, allowing easy access to the compareStrings function for string comparison.

      5. Using Openzeppelin Library

      External libraries like the OpenZeppelin Contracts’ Strings library can provide convenient and efficient functions for string manipulation and comparison. Here’s an example:

      import "@openzeppelin/contracts/utils/Strings.sol";
      
      contract StringComparison {
          using Strings for string;
      
          function compareStrings(string memory a, string memory b) 
      		public pure returns (bool) 
      		{
              return a.equal(b);
          }
      }

      In this example, the Strings library is imported from OpenZeppelin Contracts and the using Strings for string; statement is used to enable the library’s functions on the string type.

      5. Off-Chain Comparison

      Perform string comparison off-chain, outside the Ethereum blockchain, and only store the result of the comparison on-chain. This method can be more efficient regarding gas costs but requires additional infrastructure for off-chain computation.

      6. External Services

      Integrate with external services or oracles that provide string comparison functionality. This approach allows leveraging more powerful computational resources outside the Ethereum network.

      7. Preprocessing and Normalization:

      Normalize strings before comparison by converting them to a common format (e.g., lowercase) and removing any leading or trailing whitespace. This helps ensure consistent comparison results.

      🔥 Check this course out: Build Hogwarts Sorting Hat dApp on Polygon

      Complete Code — Comparing Strings in Solidity

      Let’s illustrate the string comparison process with an example:

      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      
      contract StringComparator {
          function compareStrings(string memory _a, string memory _b) public pure returns(bool) {
              return keccak256(abi.encodePacked(_a)) == keccak256(abi.encodePacked(_b));
          }
      }
      
      contract StringComparisonExample {
          StringComparator public comparator;
      
          constructor() {
              comparator = new StringComparator();
          }
      
          function compare(string memory _str1, string memory _str2) public view returns(bool) {
              return comparator.compareStrings(_str1, _str2);
          }
      }

      In this example, we have two contracts: StringComparator, which implements the string comparison logic, and StringComparisonExample, which utilizes StringComparator to compare strings.

      Limitations and Considerations

      While hashing provides a viable solution for string comparison in Solidity, there are some limitations and considerations to keep in mind:

      1. Gas costs: Hashing operations can be computationally expensive in terms of gas costs. When dealing with large strings or frequent comparisons, gas costs can accumulate quickly.
      2. Collision risk: Although SHA-256 is designed to have a low probability of hash collisions, it’s not impossible. In rare cases, different strings might produce the same hash, leading to false positives in string comparison.
      3. Encoding: Ensure that strings are encoded consistently before hashing to avoid discrepancies due to different encoding formats. Using abi.encodePacked helps ensure consistent encoding.
      4. Storage considerations: Storing hashed values may have implications for storage requirements, especially in scenarios where the same strings are compared frequently. Consider the trade-offs between storage and computation costs.

      🔥 Check this course out: Build a Semi-Fungible ERC404 Tokens’ Marketplace

      Conclusion

      In Solidity, comparing strings requires special considerations due to the underlying nature of string representation in the EVM. By leveraging cryptographic hashing techniques like SHA-256, we can effectively compare strings while mitigating some of the challenges associated with direct string comparison. However, it’s essential to be mindful of gas costs, potential hash collisions, encoding issues, and storage considerations when implementing string comparison functionality in Solidity.

      Related Reading: