2

Using Oraclize, I request a some external data in the form "1 2 3", i.e., space-separated integers (OR any other delimiter).

Indeed, these numbers could be requested one at a time, but this would be EXPENSIVE.

Now, to work with these integers, I need to convert them back to integers and store them inside an array.

I know the parseInt() function for converting a string to a number, but how to I break up the string into "1", "2", "3", such that I can parse the numbers and store them in an array?

Achala Dissanayake
  • 5,819
  • 15
  • 28
  • 38
Shuzheng
  • 1,855
  • 3
  • 19
  • 31
  • 1
    @AchalaDissanayake and other editors: I reverted the edit made in revision 2 back to OP's original wording. OP is performing a conversion of integers to strings, not a split of strings to array of strings. Also, the edit mentions an "array with a delimiter" in simplest parsing. That doesn't even make sense! Lastly, editor's title turned string into "String" (uppercase) which is inappropriate in both interpretations of the word; the type in Solidity is string and the computer-y meaning is also simply just another English word. OP's title was fine as-is. Edit adds three mistakes. – lungj Oct 08 '17 at 15:48
  • The function was generalized to use it with any separator not only with spaces. – Achala Dissanayake Oct 08 '17 at 17:02

2 Answers2

2

You may use a library like stringutils or solidity-util to for that. For your special case, casting the string to bytes and manipulating like the following function will work.

contract MyContract{

    bytes tempNum ; //temporarily hold the string part until a space is recieved
    uint[] numbers;

    function splitStr(string str, string delimiter) constant returns (int []){ //delimiter can be any character that separates the integers 

        bytes memory b = bytes(str); //cast the string to bytes to iterate
        bytes memory delm = bytes(delimiter); 

        for(uint i; i<b.length ; i++){          

            if(b[i] != delm[0]) { //check if a not space
                tempNum.push(b[i]);             
            }
            else { 
                numbers.push(parseInt(string(tempNum))); //push the int value converted from string to numbers array
                tempNum = "";   //reset the tempNum to catch the net number                 
            }                
        }

        if(b[b.length-1] != delm[0]) { 
           numbers.push(parseInt(string(tempNum)));
        }
        return numbers;
    }
}

If you can't use parseInt you may use your own function to convert to uint as follow found here,

function bytesToUint(bytes b) constant returns (uint result) {

    result = 0;
    for (uint i = 0; i < b.length; i++) { 
        if (b[i] >= 48 && b[i] <= 57) {
            result = result * 10 + (uint(b[i]) - 48); 
        }
    }
    return result;
    }

Then instead of numbers.push(parseInt(string(tempNum))); you can use numbers.push(bytesToUint(tempNum));

Or you can look into the libraries code and use only the function you need. Those might be efficient.

Hope this helps!

Achala Dissanayake
  • 5,819
  • 15
  • 28
  • 38
  • Thanks! Do you know of this library is already deployed on Rinkeby testnet? Can you describe what your code does? Is 0x20 used as a separator? What if a real byte takes this value? – Shuzheng Oct 05 '17 at 17:42
  • 0X20 is the hex value of 32 which is the char value of space , you can change the delimeter by changing that value, for your case since it's spsce I used 0x20 – Achala Dissanayake Oct 05 '17 at 17:44
  • Yes, Thank you! It is so nice, just what I needed. – Shuzheng Oct 05 '17 at 18:24
  • Your code has some minor errors, like the temp.push(). – Shuzheng Oct 05 '17 at 18:25
  • Do you think it would be more efficient to have the oracle service return the numbers as raw bytes? Then parseInt() would not be required (It is expensive, right?). Would the code look similar then? – Shuzheng Oct 05 '17 at 18:49
  • Say, each number is 4 bytes(32 bit) – Shuzheng Oct 05 '17 at 18:50
  • What I feel is then you may skip the string to bytes cast step, but if your need is to get an array of numbers you will still need to convert them to uint? You can use your own function to convert string to uint, I'll post one here as well, but you will have to compare it with the cost to use parseInt – Achala Dissanayake Oct 05 '17 at 19:10
  • Sure, please post it. :-) – Shuzheng Oct 05 '17 at 19:13
  • Last question, can you convert a “bytes” to “uint”? If so, how? By “bytes” I mean an array. – Shuzheng Oct 05 '17 at 19:17
  • Yes, but you assume the bytes are hex repr. of ASCII numbers? Say bytes contains 0x00 0x00 0x00 0xFF, then I want to convert this sequence to 255. – Shuzheng Oct 05 '17 at 19:25
  • Can’t I just cast bytes to uint? – Shuzheng Oct 05 '17 at 19:25
  • I'm not very sure. I think you may search for hex to decimal conversion using solidity. – Achala Dissanayake Oct 05 '17 at 19:32
  • Hi again, do you have any idea why your method isn't working from my code: https://pastebin.com/Lns49hLu ? – Shuzheng Oct 06 '17 at 12:39
  • I checked it in remix ide and it worked as expected, I'll check the code you posted when I get a time – Achala Dissanayake Oct 06 '17 at 14:25
  • Hi again, it works now - it was due to an exceed gas limit exception it didn't work. Oraclize set a default gas limit of 200.000, but your function cost a little more to run ;) – Shuzheng Oct 06 '17 at 16:16
  • Having looked at the stringutils library, I don't think its "split" functions seems more efficient than yours? They return one token at a time. – Shuzheng Oct 07 '17 at 09:28
  • To use stringutils, I must first deploy it onto the blockchain right? Its basic usage says using strings for *;. So, I don't inherit from stringutils? – Shuzheng Oct 07 '17 at 09:35
  • You may test the function found in library using the remix ide and find the gas cost, so you can know accurately which one is cheap. refer this question regarding libraries – Achala Dissanayake Oct 07 '17 at 11:34
  • 1
    Comments are not for extended discussion; this conversation has been moved to chat. – Badr Bellaj Oct 07 '17 at 12:10
1

You can also use solidity-util, a relatively new library:

string[] storage split = str.split(" ");