这在其他语言中可能很简单,但我不知道如何在 Solidity 中做到这一点。
我有一个 bytes32
像这样0x05416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f4a712
.
我不想将字节转换为字符串,而只想将整个内容表示为字符串,例如“0x05416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f4a712”。
如何在 Solidity 中做到这一点?
更新:
为什么我需要这样做:基本上我连接到一个预言机,它在链下做一些工作,最后上传一个文件到 IPFS。我需要将内容标识符从 oracle 获取到我的契约(Contract)中。 oracle只能发bytes32
作为回应,所以我将其转换为 multihash并且只发送 digest
如 bytes32
从预言机到合约。
到目前为止一切顺利,我可以在我的合约中重新创建多重哈希。问题是在此之后我创建了一个 ERC721
(NFT) token ,我必须在元数据中存储一些对 IPFS 文件的引用,它只能在 string
中。格式。这就是我目前被困的地方。
最佳答案
虽然@Burt 的答案看起来是正确的(虽然没有对其进行测试),但有一种更有效的方法来解决相同的任务:
function toHex16 (bytes16 data) internal pure returns (bytes32 result) {
result = bytes32 (data) & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000 |
(bytes32 (data) & 0x0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000) >> 64;
result = result & 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 |
(result & 0x00000000FFFFFFFF000000000000000000000000FFFFFFFF0000000000000000) >> 32;
result = result & 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 |
(result & 0x0000FFFF000000000000FFFF000000000000FFFF000000000000FFFF00000000) >> 16;
result = result & 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 |
(result & 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000) >> 8;
result = (result & 0xF000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000) >> 4 |
(result & 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00) >> 8;
result = bytes32 (0x3030303030303030303030303030303030303030303030303030303030303030 +
uint256 (result) +
(uint256 (result) + 0x0606060606060606060606060606060606060606060606060606060606060606 >> 4 &
0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F) * 7);
}
function toHex (bytes32 data) public pure returns (string memory) {
return string (abi.encodePacked ("0x", toHex16 (bytes16 (data)), toHex16 (bytes16 (data << 128))));
}
此代码产生大写输出。对于小写输出,只需将代码中的 7 更改为 39。说明
这个想法是使用二进制操作一次处理 16 个字节。
toHex16
函数将表示为 bytes16
值的 16 字节序列转换为表示为 bytes32
值的 32 个十六进制数字序列。 toHex
函数将 bytes32
值拆分为两个 bytes16
块,通过 toHex16
函数将每个块转换为十六进制表示,最后使用 0x
函数将 abi.encodePacked
前缀与转换后的块连接起来。最复杂的部分是
toHex16
函数的工作原理。让我们逐句解释一下。第一句话:
result = bytes32 (data) & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000 |
(bytes32 (data) & 0x0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000) >> 64;
这里我们将输入的最后 64 位右移 64 位,基本上是:0123456789abcdeffedcba9876543210
\______________/\______________/
| |
| +---------------+
______V_______ ______V_______
/ \ / \
0123456789abcdef0000000000000000fedcba9876543210
第二句话:result = result & 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 |
(result & 0x00000000FFFFFFFF000000000000000000000000FFFFFFFF0000000000000000) >> 32;
这里我们将两个 64 位块的最后 32 位向右移动 32 位:0123456789abcdef0000000000000000fedcba9876543210
\______/\______/ \______/\______/
| | | |
| +-------+ | +-------+
__V___ __V___ __V___ __V___
/ \ / \ / \ / \
012345670000000089abcdef00000000fedcba980000000076543210
下一句:result = result & 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 |
(result & 0x0000FFFF000000000000FFFF000000000000FFFF000000000000FFFF00000000) >> 16;
做:012345670000000089abcdef00000000fedcba980000000076543210
\__/\__/ \__/\__/ \__/\__/ \__/\__/
| | | | | | | |
| +---+ | +---+ | +---+ | +---+
V_ V_ V_ V_ V_ V_ V_ V_
/ \ / \ / \ / \ / \ / \ / \ / \
012300004567000089ab0000cdef0000fedc0000ba980000765400003210
下一个:result = result & 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 |
(result & 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000) >> 8;
做:012300004567000089ab0000cdef0000fedc0000ba980000765400003210
\/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/
| | | | | | | | | | | | | | | |
| +-+ | +-+ | +-+ | +-+ | +-+ | +-+ | +-+ | +-+
V V V V V V V V V V V V V V V V
/\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\
01002300450067008900ab00cd00ef00fe00dc00ba00980076005400320010
这个系列的最后一句话有点不同:result = (result & 0xF000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000) >> 4 |
(result & 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00) >> 8;
它将奇数半字节向右移动 4 位,偶数半字节向右移动 8 位:01002300450067008900ab00cd00ef00fe00dc00ba00980076005400320010
|\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V
000102030405060708090a0b0c0d0e0f0f0e0d0c0b0a09080706050403020100
因此,初始数据的所有半字节每字节分配一个。现在对于每个字节
x
我们需要进行以下转换:x` = x < 10 ? '0' + x : 'A' + (x - 10)
让我们稍微重写一下这个公式:x` = ('0' + x) + (x < 10 ? 0 : 'A' - '0' - 10)
x` = ('0' + x) + (x < 10 ? 0 : 1) * ('A' - '0' - 10)
请注意, (x < 10 ? 0 : 1)
可以计算为 ((x + 6) >> 4)
,因此我们有:x` = ('0' + x) + ((x + 6) >> 4) * ('A' - '0' - 10)
x` = (0x30 + x) + ((x + 0x06) >> 4) * 7
最后声明:result = bytes32 (0x3030303030303030303030303030303030303030303030303030303030303030 +
uint256 (result) +
(uint256 (result) + 0x0606060606060606060606060606060606060606060606060606060606060606 >> 4 &
0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F) * 7);
基本上对每个字节执行上述计算。这0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F
需要右移后的掩码将原始公式中右移“丢弃”的位清零。顺便说一句,最好在 https://ethereum.stackexchange.com/ 提出这样的问题
关于ethereum - Solidity:如何将 bytes32 表示为字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67893318/