如何在 Solidity 中将 bytes3 转换为 HEX 字符串
How to convert bytes3 to HEX string in Solidity
我之前问过 。现在我想在 bytes3
变量中存储一个 HEX 值 0x00ff08
,并能够将其转换为 Solidity 智能合约中的 string
。随后我打算将它部署在 RSK 上,Solidity 编译器版本至少为 0.8.0。
我试过这个 string(abi.encodePacked(bytes3(
0x00ff08
)))
但它抛出运行时错误
无法解码输出:null:偏移量 1 处的无效代码点;错误的代码点前缀(argument="bytes", value={"0":0,"1":255,"2":8}, code=INVALID_ARGUMENT, version=strings/5.4.0)
不同的参数string(abi.encodePacked(bytes3(
0x443322
)))
不会导致错误,但是returns一个非常奇怪的D3"
结果。这里可能是什么问题?如何将 bytes3
转换为具有相同字符的 string
?
您所观察到的行为的原因
abi.encodePacked(myBytes3)
产生 3 个字节,因为每 2 个十六进制字符产生 1 个字节。因此,当您将其包装在 string(..)
中时,您确实会得到一个每 1 个字节包含 1 个字符的字符串,在本例中,结果是包含 3 个字符的字符串。对于某些输入,这会导致 可以 呈现为人类可读字符串的字符串。在其他情况下,它会导致一个不能被解析的字符串,因此会出现解析错误。
解决方案
在这种情况下你不能使用 abi.encodePacked(..)
,因为“打包”是你想要完成的相反 - 呈现 bytes3
作为十六进制 string
- 一个人类可读的,ASCII 编码的 - 你需要做类似的事情
,其中结合使用位移位和位掩码,每半字节提取一个字符。
代码
将单个 uint8
转换为十六进制表示它的 ASCII 字符的实用函数:
function uint8tohexchar(uint8 i) public pure returns (uint8) {
return (i > 9) ?
(i + 87) : // ascii a-f
(i + 48); // ascii 0-9
}
将 uint24
转换为 6 个字符的十六进制数 string
的函数。
请注意,由于这次您不是在寻找“通用”解决方案,而是特定于 bytes3
的解决方案,因此不需要任何循环,而是顺序集的声明会做。可能也节省了一些天然气。(待确认!)
function uint24tohexstr(uint24 i) public pure returns (string memory) {
bytes memory o = new bytes(6);
uint24 mask = 0x00000f;
o[5] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[4] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[3] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[2] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[1] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[0] = bytes1(uint8tohexchar(uint8(i & mask)));
return string(o);
}
最后,您可能需要一个明确接受 bytes3
作为参数的函数。
请注意,这纯粹是为了方便起见,因为它实际上所做的只是类型转换。 bytes3
和 uint24
可以简单地视为以不同方式查看/解释的“24 位”。
function bytes3tohexstr(bytes3 i) public pure returns (string memory) {
uint24 n = uint24(i);
return uint24tohexstr(n);
}
我之前问过 bytes3
变量中存储一个 HEX 值 0x00ff08
,并能够将其转换为 Solidity 智能合约中的 string
。随后我打算将它部署在 RSK 上,Solidity 编译器版本至少为 0.8.0。
我试过这个 string(abi.encodePacked(bytes3(
0x00ff08
)))
但它抛出运行时错误
无法解码输出:null:偏移量 1 处的无效代码点;错误的代码点前缀(argument="bytes", value={"0":0,"1":255,"2":8}, code=INVALID_ARGUMENT, version=strings/5.4.0)
不同的参数string(abi.encodePacked(bytes3(
0x443322
)))
不会导致错误,但是returns一个非常奇怪的D3"
结果。这里可能是什么问题?如何将 bytes3
转换为具有相同字符的 string
?
您所观察到的行为的原因
abi.encodePacked(myBytes3)
产生 3 个字节,因为每 2 个十六进制字符产生 1 个字节。因此,当您将其包装在 string(..)
中时,您确实会得到一个每 1 个字节包含 1 个字符的字符串,在本例中,结果是包含 3 个字符的字符串。对于某些输入,这会导致 可以 呈现为人类可读字符串的字符串。在其他情况下,它会导致一个不能被解析的字符串,因此会出现解析错误。
解决方案
在这种情况下你不能使用 abi.encodePacked(..)
,因为“打包”是你想要完成的相反 - 呈现 bytes3
作为十六进制 string
- 一个人类可读的,ASCII 编码的 - 你需要做类似的事情
代码
将单个 uint8
转换为十六进制表示它的 ASCII 字符的实用函数:
function uint8tohexchar(uint8 i) public pure returns (uint8) {
return (i > 9) ?
(i + 87) : // ascii a-f
(i + 48); // ascii 0-9
}
将 uint24
转换为 6 个字符的十六进制数 string
的函数。
请注意,由于这次您不是在寻找“通用”解决方案,而是特定于 bytes3
的解决方案,因此不需要任何循环,而是顺序集的声明会做。可能也节省了一些天然气。(待确认!)
function uint24tohexstr(uint24 i) public pure returns (string memory) {
bytes memory o = new bytes(6);
uint24 mask = 0x00000f;
o[5] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[4] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[3] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[2] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[1] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[0] = bytes1(uint8tohexchar(uint8(i & mask)));
return string(o);
}
最后,您可能需要一个明确接受 bytes3
作为参数的函数。
请注意,这纯粹是为了方便起见,因为它实际上所做的只是类型转换。 bytes3
和 uint24
可以简单地视为以不同方式查看/解释的“24 位”。
function bytes3tohexstr(bytes3 i) public pure returns (string memory) {
uint24 n = uint24(i);
return uint24tohexstr(n);
}