0

Since Solidity functions can't accept String Arrays as arguments, I'm trying instead to pass in a long comma-delimited string, and then convert it to an array of strings on the fly.

I'm close - but the one line in the else statement towards the bottom - which I've pointed out in a comment - keeps crashing the contract.

Here's my code:

function splitString(string calldata stringToSplit) external pure returns(string memory) {
    // 1. Declare a string array to hold all the individual words I'm able to tease 
    //    out of the passed-in string: 
    string[] memory finalWordsArray;
    
    // 2. Declare a word-counter var to keep track of how many words I've gotten:
    uint256 wordCounter = 0;

    // 3. Convert and store the passed-in String argument into a Bytes Array so 
    //    I can iterate through it one character at a time:
    bytes memory stringAsBytesArray = bytes(stringToSplit);

    // 4. Declare another bytes array to contain all the characters that will be
    //    in my next full individual Word:
    string memory tmp = new string(stringAsBytesArray.length);
    bytes memory tempWord = bytes(tmp);
    
    
    // 5. Iterate through the "stringAsBytesArray" one Char at a time:
    // ["Hello,here,we,are,today"]
    for(uint i = 0; i < stringAsBytesArray.length; i++) {
        // if current char is NOT a comma, append it to my "tempWord":
        if (stringAsBytesArray[i] != ",") {
            tempWord[i] = stringAsBytesArray[i];
        }
        else {
            // We found a Comma, which means we've reached the end of a word. So 
            // let's convert our "tempWord" from a bytes Array to a String:
            string memory newWord = string(tempWord);
            
            // And then add that word to our "finalWordsArray":  
            // -->this next line causes a crash!
            // finalWordsArray[wordCounter] = newWord;
            
            // Iterate our wordCounter:
             wordCounter++;
             
            // And reset/blank-out our "tempWord" for the next go-around:
            tempWord = bytes(tmp);
            

            // This next statement DOES work: it returns the first word it
            // found before hitting that first comma. I put this in just to
            // see that I am getting at least SOMETHING out of this:
            return newWord;
        }
    }

    return "no Commas found!!!";

    // return string(finalWordsArray[2]);
}
1

Since Solidity functions can't accept String Arrays as arguments

This technically doesn't answer your question, but if you enable ABIEncoderV2 you can simply pass a string array to a function, rather than trying to split it yourself. This is likely a lot more efficient with regards to gas usage.

For example:

pragma solidity ^0.7.4;
pragma experimental ABIEncoderV2;

contract Foo {
  function bar (string[] calldata baz) public {
    // do something with `baz` here 
  }
}
5
  • Yeah, I'm familiar with that - I've used it in other test projects in the past, but nothing I officially published/deployed. Cause my understanding what that this experimental ABIEncoderV2 has some security flaws. Doesn't it? – Mark55 Nov 11 '20 at 17:45
  • It was an experimental API until Solidity version 0.6.0. Starting with that version it's not considered experimental anymore so it should be safe to use. It's not enabled by default yet though, IIRC that's because it can cause breaking changes. – Morten Nov 11 '20 at 19:21
  • Interesting - I didn't know the status on experimental ABIEncoderV2 changed. Will have to look into that and perhaps reconsider. Of course, this props up another question: any idea what the SIZE-LIMIT is on the string-arrays we can pass into functions under ABIEncoderV2? 🤓 – Mark55 Nov 12 '20 at 16:03
  • As far as I know Solidity doesn't have a hard limit for string length or array size, you're more likely to be limited by the transaction cost to send the data to the contract. – Morten Nov 12 '20 at 17:08
  • Right, gas/cost limits - of course! That's what it ALL comes down to with Ethereum, doesn't it? 🤓 Guess it's time for some good old fashioned gasEstimate type trials... 🤔 – Mark55 Nov 12 '20 at 17:31
0

The problem is that finalWordsArray is never allocated so it is empty and you can't assign items to any index. For the assignments to work you have to allocate finalWordsArray with enough entries. Unfortunately memory arrays are not dynamic and you cannot change its length once it was initialized.

Probably the best option is to use ABIEncoverV2 as @Morten said or use solidity-stringutils to avoid parsing by hand.

4
  • I'm familiar with solidity-stringutils - but it's like 3 years old and compiles with pragma 0.4.x which means changing the solc compiler settings in my truffle-config file, which then meant having to change the pragma statements in ALL my project's files - and there are lots. (I'm using OpenZeppelin library files, so there are lotsa dependencies.) So I tried doing that and got errors all over the place - and frankly, I never really understood how to deal with that. Meaning with "mixing pragmas". Is that possible? Is it ok to do? Or not-advisable? – Mark55 Nov 12 '20 at 16:01
  • @Mark55 Probably the best options would be to upgrade solidity-stringutils to 0.5 or 0.6, it should be straightforward. – Ismael Nov 12 '20 at 17:34
  • Wait a minute, you're suggesting I upgrade the pragma statement in the original solidity-stringutils files to 0.5 or 0.6 and that'll fix things? Cause my assumption would be that doing something like that would wreak havoc and break everything in solidity-stringutils... So is that what you meant, or did I misunderstand? – Mark55 Nov 12 '20 at 18:31
  • @Mark55 Unfortunately it is not that easy, but there's a pull request with required changes, so you can apply those changes locally in your copy. – Ismael Nov 12 '20 at 19:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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