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?

Carlos Fuentes
  • 176
  • 1
  • 2
  • 15

5 Answers5

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.

Rob Hitchens
  • 55,151
  • 11
  • 89
  • 145
  • 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. – Станислав Тепляков May 23 '19 at 07: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. – Rob Hitchens May 23 '19 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 = &quot; &quot;;
bytes memory spaceByte = bytes(space);

uint j = 0; 

for (uint i=0; i &lt; 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 &lt; bstr.length; i++) {
    if (bstr[i] != ' ') {
        output[j] = bstr[i];
        j += 1;
    }
}
return string(output);

}

NarC_
  • 11
  • 3
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.

Antonio Carito
  • 2,445
  • 3
  • 10
  • 23
  • The function has some problems, it doesn't allocate memory for Result. – Ismael May 31 '22 at 03: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 May 31 '22 at 08: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();
}

}

David Wolf
  • 103
  • 3
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.

Adam Boudj
  • 2,361
  • 1
  • 8
  • 21