Cómo convertir un bytes32 a cadena

¿Cómo puedo convertir un bytes32a un string? ¿Alguien tiene una función mágica o una biblioteca que lo haga?

Esto de concatenar, ¿no?
¿Es esta una pregunta de solidez o fuera de la cadena de bloques, por ejemplo, en javascript?
No, solo en la cadena de bloques. Hice otra pregunta con la parte js

Respuestas (11)

Basado en la última versión del compilador 0.4.24, uso lo siguiente.

function convertingToString()public returns(string){
bytes32 memory hw = "Hello World";
string memory converted = string(hw);
return converted;
}

Usando conversión explícita para llevarlo a cabo. También es posible lo contrario.

Para las versiones 0.5.0+, utilice (probado de 0.5 a 0.7.2; es probable que continúe funcionando después de 0.7.2):

function bytes32ToString(bytes32 _bytes32) public pure returns (string memory) {
        uint8 i = 0;
        while(i < 32 && _bytes32[i] != 0) {
            i++;
        }
        bytes memory bytesArray = new bytes(i);
        for (i = 0; i < 32 && _bytes32[i] != 0; i++) {
            bytesArray[i] = _bytes32[i];
        }
        return string(bytesArray);
    }
Esto no funciona en solidity versión 0.5.0+
y que hace??
actualizado para la versión de solidez anterior a 0.5.0
no funciona obteniendo este error ` Error al decodificar la salida: nulo: punto de código no válido en el desplazamiento 2; falta el byte de continuación (argumento="bytes", valor={"0":91,"1":218,"2":113,"3":98,"4":184,"5":77," 6":255,"7":114,"8":27,"9":203,"10":143,"11":119,"12":114,"13":120,"14" :180,"15":136,"16":222,"17":216,"18":209,"19":71,"20":82,"21":100,"22":212 ,"23":54,"24":28,"25":107,"26":10,"27":191,"28":204,"29":42,"30":153," 31":168}, code=INVALID_ARGUMENT, version=strings/5.1.0) ` estaba tratando de convertir esta cadena0x5bda7162b84dff721bcb8f777278b488ded8d1475264d4361c6b0abfcc2a99a8

A partir de febrero de 2021 puedes hacerlo

bytes32 foo = "hello";
string memory bar = string(abi.encodePacked(foo));
Tan pronto como StackOverfloor obtenga el voto del sistema de Medium, daré otros 10 votos a favor.
No se pudo decodificar la salida: nulo: punto de código no válido en el desplazamiento 2; Falta el byte de continuación (argumento="bytes"....
desafortunadamente, mantiene cero relleno, lo que podría ser un problema en algunos casos.

Aquí hay uno:

function bytes32ToString(bytes32 x) constant returns (string) {
    bytes memory bytesString = new bytes(32);
    uint charCount = 0;
    for (uint j = 0; j < 32; j++) {
        byte char = byte(bytes32(uint(x) * 2 ** (8 * j)));
        if (char != 0) {
            bytesString[charCount] = char;
            charCount++;
        }
    }
    bytes memory bytesStringTrimmed = new bytes(charCount);
    for (j = 0; j < charCount; j++) {
        bytesStringTrimmed[j] = bytesString[j];
    }
    return string(bytesStringTrimmed);
}

Para probar, aquí se combina con cómo concatenar una matriz debytes32 . Pega lo siguiente en Remix .

contract C {
    function bytes32ToString(bytes32 x) constant returns (string) {
        bytes memory bytesString = new bytes(32);
        uint charCount = 0;
        for (uint j = 0; j < 32; j++) {
            byte char = byte(bytes32(uint(x) * 2 ** (8 * j)));
            if (char != 0) {
                bytesString[charCount] = char;
                charCount++;
            }
        }
        bytes memory bytesStringTrimmed = new bytes(charCount);
        for (j = 0; j < charCount; j++) {
            bytesStringTrimmed[j] = bytesString[j];
        }
        return string(bytesStringTrimmed);
    }

    function bytes32ArrayToString(bytes32[] data) returns (string) {
        bytes memory bytesString = new bytes(data.length * 32);
        uint urlLength;
        for (uint i=0; i<data.length; i++) {
            for (uint j=0; j<32; j++) {
                byte char = byte(bytes32(uint(data[i]) * 2 ** (8 * j)));
                if (char != 0) {
                    bytesString[urlLength] = char;
                    urlLength += 1;
                }
            }
        }
        bytes memory bytesStringTrimmed = new bytes(urlLength);
        for (i=0; i<urlLength; i++) {
            bytesStringTrimmed[i] = bytesString[i];
        }
        return string(bytesStringTrimmed);
    }    
}

Haz clic en "Crear". Luego en bytes32ToStringel campo ingrese "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"y haga clic en bytes32ToString.

En bytes32ArrayToStringel campo ingrese ["0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]y haga clic en bytes32ArrayToString.

Ambos mostrarán el mismo resultado (codificación ABI): Resultado:"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"


Aquí hay otro ejemplo. En bytes32ToStringel campo ingrese "0xc3b6"y haga clic en bytes32ToString. obtendrás ö_

ingrese la descripción de la imagen aquí

Usé la función bytes32ToString de arriba, pero obviamente no funciona con caracteres especiales como ö ä ü, etc. ¿Hay alguna forma de usar esta función con caracteres especiales?
@Bumblebee Agregué un ejemplo para ö y funciona. Si aún es necesario, probablemente haga una pregunta por separado. (La entrada o la decodificación de la salida podría ser su problema).
Lo estoy probando bytes32ArrayToStringcon un fijo bytes32[10], pero parece que arrojo un invalid opcodesi uso 8-10 ranuras completas de la matriz. Lo que significa que tengo una prueba para abcdefghijklmnopqrstuvwxyzabcdef(32 caracteres) 10 veces en una matriz y la paso, pero arroja. Si tengo 7 o menos funciona. ¿Alguna idea de por qué?
@TheNomad No estoy seguro. Sugerencias, intente una vez en lugar de 10 veces y publique una nueva pregunta (un enlace Remix o ethfiddle podría ayudar).
@Russo No está claro qué estás tratando de hacer en Python; Stackoverflow se adapta mejor a las preguntas sobre la conversión de diferentes tipos de Python.
No tenía idea de que una cadena era una matriz de bytes. ¡Aprendí algo nuevo hoy! ¡Gracias!

Cómo convertir un bytes32 a cadena:

pragma solidity ^0.4.15;

contract Bytes32ToString {

function bytes32ToStr(bytes32 _bytes32) public pure returns (string) {

    // string memory str = string(_bytes32);
    // TypeError: Explicit type conversion not allowed from "bytes32" to "string storage pointer"
    // thus we should fist convert bytes32 to bytes (to dynamically-sized byte array)

    bytes memory bytesArray = new bytes(32);
    for (uint256 i; i < 32; i++) {
        bytesArray[i] = _bytes32[i];
        }
    return string(bytesArray);
    }

}

Como @ e18r ya mencionado, la forma más sencilla de hacerlo sin tener que escribir todas estas funciones locas con las que todos los demás están respondiendo (y costaría más gasolina), simplemente hazlo:

string(abi.encodePacked(bytes32));

desafortunadamente, parece mantener un relleno cero, lo que podría ser un problema en algunos casos.

Se recomienda convertir un bytes32a a stringusando Web3.js para evitar costos de gasolina. Para hacer esto, obtendría el valor de bytes32Solidity en el front-end y luego haría:

web3.utils.hexToString(bytes32);

Esto convertirá el bytes32a un stringque luego puede ver y usar en su dApp frontend.

Por si acaso, si desea convertir bytes32 a una cadena ASCII, puede usar la biblioteca OpenZeppelin Strings.

https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2504

Strings.toHexString(uint256(tokenIdSeed), 32),

La salida debería ser como

0xd8df8ecd5432b247d2fc2beb0619d637e9de0df7512bd36220582deda9a1df6e 

(esto es solo un valor hexadecimal encubierto de los bytes32 a la cadena)

Esta es la solución más simple y elegante entre todas las respuestas. ¡Gracias!

En la versión 0.5.0 y superior, terminé usando la respuesta de Viktor Cómo convertir un bytes32 en una cadena pero eliminando los ceros ; de lo contrario, terminará con

'ERC20\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000'

en vez de

'ERC20'

Este es el código:

/* bytes32 (fixed-size array) to string (dynamically-sized array) */
function bytes32ToString(bytes32 _bytes32) public pure returns (string memory) {
        uint8 i = 0;
        while(i < 32 && _bytes32[i] != 0) {
            i++;
        }
        bytes memory bytesArray = new bytes(i);
        for (i = 0; i < 32 && _bytes32[i] != 0; i++) {
            bytesArray[i] = _bytes32[i];
        }
        return string(bytesArray);
    }

Un método más eficiente en gas basado en esta respuesta (para versiones 0.5.0+):

function toString(bytes32 source)
    internal
    pure
    returns (string memory result)
{
    uint8 length = 0;
    while (source[length] != 0 && length < 32) {
        length++;
    }
    assembly {
        result := mload(0x40)
        // new "memory end" including padding (the string isn't larger than 32 bytes)
        mstore(0x40, add(result, 0x40))
        // store length in memory
        mstore(result, length)
        // write actual data
        mstore(add(result, 0x20), source)
    }
}

Esta solución utiliza ensamblaje para copiar datos en la memoria en lugar de hacer un forbucle.

Así es como lo estoy haciendo:

function char(byte b) returns (byte c) {
    if (b < 10) return byte(uint8(b) + 0x30);
    else return byte(uint8(b) + 0x57);
}


function bytes32string(bytes32 b32) returns (string out) {
    bytes memory s = new bytes(64);

    for (var i = 0; i < 32; i++) {
        byte b = byte(b32[i]);
        byte hi = byte(uint8(b) / 16);
        byte lo = byte(uint8(b) - 16 * uint8(hi));
        s[i*2] = char(hi);
        s[i*2+1] = char(lo);            
    }

    out = string(s);
}
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    contract stringtobytes{
        function set(string memory  _a)public pure returns(bytes memory){
            return bytes(_a);
        } 
         function set1(bytes memory  _a)public pure returns(string  memory){
            return string(_a);
        } 

}

// puede convertir cadenas a bytes (en formato decimal) y viceversa con el siguiente código

//1- bytes1=8bit=2decimal

//2 bytes2=16bit=4decimales

//3 bytes3=24bit=6decimal

//4 bytes=matriz dinámica y valor de referencia

La pregunta es sobre la conversión de bytes32 a cadena, y su ejemplo no funciona para eso.