Cómo convertir una cadena a int

¿Cómo convierto una cadena en un int? aquí está mi código:

   pragma solidity ^0.4.6;

contract MyContract {
    string public a;
    /* Constructor */
    function MyContract() {
        a = "0.12312317314571638713891378174163782169246891247193811231231731";
    }

    function bytesToUInt(uint v) constant returns (uint ret) {
    if (v == 0) {
        ret = 0;
    }
    else {
        while (v > 0) {
            ret = uint(uint(ret) / (2 ** 8));
            ret |= uint(((v % 10) + 48) * 2 ** (8 * 31));
            v /= 10;
        }
    }
    return ret;
}

    function get() constant returns(string){
        return a;
    }
}

Respuestas (7)

Tenga en cuenta que los números de coma flotante no son compatibles con Solidity y la máquina virtual Ethereum en este momento.

Si bien su pregunta es sobre la conversión de a stringa int, su código de muestra se refiere en uintlugar de a int, por lo que proporcionaré la solución para convertir una cadena a uint.

La siguiente es una solución para convertir un número de coma no flotante de una cadena a un uint(que es un uint256). He agregado la solución a esta pregunta a mi solución para Solidity concatenate uint en una cadena. :

pragma solidity ^0.4.4;

contract TestIntToString {

    string public uintToStringResult;
    string public appendUintToStringResult;
    uint public stringToUintResult;

    function TestIntToString() {
        uintToStringResult = uintToString(12345678901234567890);
        appendUintToStringResult = appendUintToString("My integer is: ", 1234567890);
        stringToUintResult = stringToUint("12312317314571638713891378174163782169246891247193811231231731");
    }

    function uintToString(uint v) constant returns (string str) {
        uint maxlength = 100;
        bytes memory reversed = new bytes(maxlength);
        uint i = 0;
        while (v != 0) {
            uint remainder = v % 10;
            v = v / 10;
            reversed[i++] = byte(48 + remainder);
        }
        bytes memory s = new bytes(i + 1);
        for (uint j = 0; j <= i; j++) {
            s[j] = reversed[i - j];
        }
        str = string(s);
    }

    function appendUintToString(string inStr, uint v) constant returns (string str) {
        uint maxlength = 100;
        bytes memory reversed = new bytes(maxlength);
        uint i = 0;
        while (v != 0) {
            uint remainder = v % 10;
            v = v / 10;
            reversed[i++] = byte(48 + remainder);
        }
        bytes memory inStrb = bytes(inStr);
        bytes memory s = new bytes(inStrb.length + i + 1);
        uint j;
        for (j = 0; j < inStrb.length; j++) {
            s[j] = inStrb[j];
        }
        for (j = 0; j <= i; j++) {
            s[j + inStrb.length] = reversed[i - j];
        }
        str = string(s);
    }

    function stringToUint(string s) constant returns (uint result) {
        bytes memory b = bytes(s);
        uint i;
        result = 0;
        for (i = 0; i < b.length; i++) {
            uint c = uint(b[i]);
            if (c >= 48 && c <= 57) {
                result = result * 10 + (c - 48);
            }
        }
    }
}

Y aquí está la captura de pantalla de Browser Solidity que muestra que la solución funciona:

ingrese la descripción de la imagen aquí

Al convertir una cadena a uInt, uint c = uint(b[i]);debe estar dentro del ifcondicional, en caso de que alguien intente pasar un número no entero como argumento. El ifdebe probar el b[i].
Además, en uInt to string, bytes memory s = new bytes(i + 1);es incorrecto. En cambio, bytes memory s = new bytes(i);con reversed[i - j - 1]es correcto.
Por último, su código falla porque los documentos dicen Index access: If x is of type bytesI, then x[k] for 0 <= k < I returns the k th byte (read-only).que no puede sobrescribir una bytematriz. NO use este código.
Gracias por revisar y proporcionar una solución alternativa.

Parte del código de BokkyPooBah es incorrecto.

Aquí están las funciones para convertir uInt a cadena y viceversa, junto con mis comentarios:

function stringToUint(string s) constant returns (uint) {
    bytes memory b = bytes(s);
    uint result = 0;
    for (uint i = 0; i < b.length; i++) { // c = b[i] was not needed
        if (b[i] >= 48 && b[i] <= 57) {
            result = result * 10 + (uint(b[i]) - 48); // bytes and int are not compatible with the operator -.
        }
    }
    return result; // this was missing
}

function uintToString(uint v) constant returns (string) {
    uint maxlength = 100;
    bytes memory reversed = new bytes(maxlength);
    uint i = 0;
    while (v != 0) {
        uint remainder = v % 10;
        v = v / 10;
        reversed[i++] = byte(48 + remainder);
    }
    bytes memory s = new bytes(i); // i + 1 is inefficient
    for (uint j = 0; j < i; j++) {
        s[j] = reversed[i - j - 1]; // to avoid the off-by-one error
    }
    string memory str = string(s);  // memory isn't implicitly convertible to storage
    return str;
}

Alguien publicó la forma en que la biblioteca de Oraclize convierte una cadena en uint aquí: http://remebit.com/converting-strings-to-integers-in-solidity/

Hay una función parseInt() en el contrato base de la API de Oraclize.

¿Se recomienda usar oraclize en 2018?
Copiar esta función del contrato de Oraclize no significa que confíe en Oraclize, así que no creo que importe. Sobre el tema de si se recomienda o no Oraclize, probablemente sea mejor formularlo como una pregunta independiente.

biblioteca ConvertStringToUint {

function stringToUint(string _amount) internal constant returns (uint result) {
    bytes memory b = bytes(_amount);
    uint i;
    uint counterBeforeDot;
    uint counterAfterDot;
    result = 0;
    uint totNum = b.length;
    totNum--;
    bool hasDot = false;

    for (i = 0; i < b.length; i++) {
        uint c = uint(b[i]);

        if (c >= 48 && c <= 57) {
            result = result * 10 + (c - 48);
            counterBeforeDot ++;
            totNum--;
        }

        if(c == 46){
            hasDot = true;
            break;
        }
    }

    if(hasDot) {
        for (uint j = counterBeforeDot + 1; j < 18; j++) {
            uint m = uint(b[j]);

            if (m >= 48 && m <= 57) {
                result = result * 10 + (m - 48);
                counterAfterDot ++;
                totNum--;
            }

            if(totNum == 0){
                break;
            }
        }
    }
     if(counterAfterDot < 18){
         uint addNum = 18 - counterAfterDot;
         uint multuply = 10 ** addNum;
         return result = result * multuply;
     }

     return result;
}

}

Para solidez 0.8.6

function stringToUint(string memory s) public pure returns (uint) {
        bytes memory b = bytes(s);
        uint result = 0;
        for (uint256 i = 0; i < b.length; i++) {
            uint256 c = uint256(uint8(b[i]));
            if (c >= 48 && c <= 57) {
                result = result * 10 + (c - 48);
            }
        }
        return result;
    }

He escrito un mejor código para manejar la bytesconversión con offsety length. El punto bueno es que mantiene el orden de los bytes.

/**
* Convert bytes to uint
* @param _data bytes Byte array
* @param _offset uint256 Position to convert 
* @param _length uint256 Data length
*/
function toUint(bytes _data, uint256 _offset, uint256 _length)
internal pure
returns(uint256 _result) {
    require(_offset >= 0);
    require(_length > 0);
    require((_offset + _length) <= _data.length);
    uint256 _segment = _offset + _length;
    uint256 count = 0;
    for (uint256 i = _segment; i > _offset ; i--) {
        _result |= uint256(_data[i-1]) << ((count++)*8);
    }
}
TypeError: conversión de tipo explícita no permitida de "bytes1" a "uint256"