2

I perform an Oraclize query on an XML file, and receive this string in return:

["31", "25", "24"]

What would be the most efficient way to parse through this string and store the numbers into a uint8 array using the minimum amount of gas?

Or is there a better way to go about this problem?
If so, please include examples.

Note:
I'm not looking to process millions of numbers this way, just around 100 or so.

2
  • Do you want to convert array of strings to the array of integers? Or do you have this array like one string? Commented Jun 1, 2018 at 9:45
  • Right. I want to extract the numbers out of this string, and put them into a uint8 array. Commented Jun 1, 2018 at 20:37

1 Answer 1

3

Since the type returned is a string, the numbers are stored in a dynamic bytes array. This means that each character occupies a single byte slot. The ASCII/UTF-8 bit representation of numbers is linearly increasing, you can parse the numbers as follows:

pragma solidity ^0.4.24;

contract NumParser {
    string[] public numArray;
    uint256[] public shouldBe;

    constructor() public {
        numArray.push("31");
        numArray.push("25");
        numArray.push("24");
        shouldBe.push(31);
        shouldBe.push(25);
        shouldBe.push(24);
        uint256[] memory result = parseNums(numArray);
        for (uint256 i = 0; i < result.length; i++) {
            assert(result[i] == shouldBe[i]);
        }
    }

    function parseNums(string[] numsToParse) internal pure returns (uint256[]) {
        uint256[] memory parsed = new uint256[](numsToParse.length);
        for (uint256 i = 0; i < numsToParse.length; i++) {
            bytes memory temp = bytes(numsToParse[i]);
            for (uint256 j = 0; j < temp.length; j++) {
                parsed[i] += (uint256(temp[j]) - 48) * (10**(temp.length - 1 - j));
            }
        }
        return parsed;
    }
}

The constructor contains a verification test that the function does indeed work correctly. The function you want to use is the parseNums function.

EDIT: You should change your original question to include that you are receiving the array in string format.

I have altered my function to work with your array as follows:

pragma solidity ^0.4.24;

contract NumParser {
    string public numArray;
    uint256[] private tempContainer;
    uint256[] public shouldBe;

    constructor() public {
        numArray = "[\"31\", \"25\", \"24\"]";
        shouldBe.push(31);
        shouldBe.push(25);
        shouldBe.push(24);
        uint256[] memory result = parseNums(numArray);
        tempContainer.length = 0;
        for (uint256 i = 0; i < result.length; i++) {
            assert(result[i] == shouldBe[i]);
        }
    }

    function parseNums(string numsToParse) internal returns (uint256[]) {
        bytes memory converted = bytes(numsToParse);
        for (uint256 i = 0; i < converted.length; i++) {
            if (converted[i] == 34) {
                tempContainer.push(0);
                uint256 j = i + 1;
                for (; converted[j] != 34; j++) {
                    tempContainer[tempContainer.length - 1] += (uint256(converted[j]) - 48);
                    tempContainer[tempContainer.length - 1] *= 10;
                }
                tempContainer[tempContainer.length - 1] /= 10;
                i = j;
            }
        }
        return tempContainer;
    }
}

Keep in mind that processing a string like this is quite costly. You also cannot use a memory array compared to the first solution because memory arrays need to have a pre-declared size while you cannot find the amount of numbers you are going to get in your array from the raw string.

This also increases the gas cost so I would advise zeroing the length as shown within the constructor to reduce the cost.

2
  • 1
    This solves the problem of converting a string of numbers to uints. But my main problem here is taking the string ["31", "25", "24"] and extracting the numbers out of there and putting them into a uint8 array. So I guess what would need to be done to ignore the [, ], ", and , characters whilst still extracting the numbers and converting them to uint8s? Commented Jun 1, 2018 at 20:42
  • 1
    Your question is ambiguous, you never specify that it is a string nor do you have it in escaped format i.e.: "[\"31\", \"25\", \"24\"]" I edited my answer according to your additional specifications. Commented Jun 2, 2018 at 11:22

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.