3

I have a function where one of its arguments is a string. How would I check the string for leading and trailing whitespaces and remove those characters?

If i get something like this:

"    " => ""

or

"     foo" => "foo"

or

"foo     " => "foo"

In PHP I can use the method trim and it returns the string with whitespaces stripped from the beginning and end.

I did not find any solution on StackExchange.

How do I do a trim in solidity?

5

5 Answers 5

5

Unless there is a very solid argument, I would suggest setting this concern aside. The main reasons.

  1. clients can and should send valid inputs
  2. Immutable contracts can and should be as simple as possible as a first line of defense against defects, so don't load them up with concerns that clients can and should attend to.
  3. Whatever processing happens in the contract will cost gas. With few exceptions, economics requires that clients with (essentially) free and plentiful processing power should be subordinate to the contract's preferred types and input requirements which are optimized for performance, readability and reliability.
  4. Usually, string is a terrible type for anything associated with application integrity. Sometimes it makes sense to store such things on chain in the interest of minimizing complexity. They are frequently candidates for off-chain storage because they are of no importance to contract logic.

TL;DR;

Garbage in, garbage out is a good policy for a contract.

Hope it helps.

2
  • 1
    Hi, thanks for you answer. You right, everyone should handle data on client side and send it, but someone can call my contracts methods and send wrong data. For example i have online game and i want to create some rating module. There are a lot of user names and someone created empty user name, and it'll looks like a bug. And i would like to avoid it. I know, it can take some commission but still it's very interesting task. Commented May 23, 2019 at 7:47
  • 1
    A second thing to think about would input validation. Maybe check if the first byte is a space and revert. I would also challenge the use of usernames in Ethereum. This whole issue can be avoided if the system doesn't do that. Legacy systems can be extended to associate ethereum addresses with user profiles if you need to. Commented May 23, 2019 at 14:38
1

It is my solution with solidity >=0.7.0 <0.9.0, maybe if you want print inputBytes[i] or spaceByte[0] you can import hardhat library (import"hardhat/console.sol";), use console.logBytes1() and change "pure" for "view" in the function definition:

 function deleteAllSpaces(string memory _text) public pure returns (string memory) {
    bytes memory inputBytes = bytes(_text);
    bytes memory output = new bytes(inputBytes.length);

    /*
     * Cast space character to byte(0x20) for compare
     */
    string memory space = " ";
    bytes memory spaceByte = bytes(space);
    
    uint j = 0; 

    for (uint i=0; i < inputBytes.length; i++) {
        if (inputBytes[i] != spaceByte[0]) {
            output[j] = inputBytes[i];
            j += 1;
        }
        
    }

    return string(output);    
}

Other solution with solidity >=0.7.0 <0.9.0:

function deleteAllSpaces(string memory str) public pure returns (string memory) {
    bytes memory bstr = bytes(str);
    bytes memory output = new bytes(bstr.length);
    uint j = 0;

    for (uint i; i < bstr.length; i++) {
        if (bstr[i] != ' ') {
            output[j] = bstr[i];
            j += 1;
        }
    }
    return string(output);
}
0

Here is a function in Solidity that I created to do just this. Typecast your string to bytes, and feed it into this function.

function byteSlice(bytes memory _data, uint256 _start, uint256 _end) internal pure returns(bytes memory Result) {
        if(_end>_data.length) {_end=_data.length;}
        for(uint i=_start;i<_end;i++) {Result[i] = _data[i];}
    }

Call the function like this:

_myString = string(byteSlice(bytes(_myString),0,6));

That's it. Hope this helps. You should know how long the string should be.

2
  • The function has some problems, it doesn't allocate memory for Result.
    – Ismael
    Commented May 31, 2022 at 3:28
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented May 31, 2022 at 8:48
0

Apart from the practical usage of such functionality, here is an implementation of ltrim, rtrim and trim: Library source

Usage example

// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.17;

import "github.com/devidw/sol-utils/src/Strings.sol";

contract A {
    using Strings for string;

    function a(string memory _str) external pure returns (string[3] memory _out) {
        _out[0] = _str.ltrim();
        _out[1] = _str.rtrim();
        _out[2] = _str.trim();
    }
}
0

Here's a shorter, gas-efficient answer without for loops:

function trim(string calldata str, uint start, uint end) external pure returns(string memory) {
    return str[start:end];
}

This takes a string and start and end positions to trim the given string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.