如何在 solidity 中将 uint 转换为字符串?
How to convert uint to string in solidity?
在 Solidity 中,有没有办法将我的 int 转换为字符串?
示例:
pragma solidity ^0.4.4;
contract someContract {
uint i;
function test() pure returns (string) {
return "Here and Now is Happiness!";
}
function love() pure returns(string) {
i = i +1;
return "I love " + functionname(i) + " persons" ;
}
}
函数名是什么?谢谢!
这里的两位post给出了回复:
https://ethereum.stackexchange.com/questions/10811/solidity-concatenate-uint-into-a-string
https://ethereum.stackexchange.com/questions/10932/how-to-convert-string-to-int
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);
}
此致
已接受答案的评论中建议的 provable-things 代码对我有用,但我的 linter 发出了警告,即:"uintToStr": Avoid assigning to function parameters. [security/no-assign-params]
。下面稍微更改原始代码以更正此问题(将参数 _i
重新分配给另一个名为 number
的变量):
/// @notice converts number to string
/// @dev source: https://github.com/provable-things/ethereum-api/blob/master/oraclizeAPI_0.5.sol#L1045
/// @param _i integer to convert
/// @return _uintAsString
function uintToStr(uint _i) internal pure returns (string memory _uintAsString) {
uint number = _i;
if (number == 0) {
return "0";
}
uint j = number;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (number != 0) {
bstr[k--] = byte(uint8(48 + number % 10));
number /= 10;
}
return string(bstr);
}
Solidity 0.8.0 更新:
https://github.com/provable-things/ethereum-api/blob/master/provableAPI_0.6.sol 中的 uint2str()
函数现已过时,无法使用,但这是使用 solidity 0.8.0 的更新代码:
(在上一个版本中有一个溢出错误,但 solidity <0.8.0 忽略了它,因为它不影响答案,但现在会抛出错误)
byte
也更改为 bytes1
和 +、-、* 等等,就像它们在 SafeMath 库中一样。
function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len;
while (_i != 0) {
k = k-1;
uint8 temp = (48 + uint8(_i - _i / 10 * 10));
bytes1 b1 = bytes1(temp);
bstr[k] = b1;
_i /= 10;
}
return string(bstr);
}
Concrete_Buddhas 答案在 solidity 0.8.0 中不起作用。这是修订版:
function uint2str(
uint256 _i
)
internal
pure
returns (string memory str)
{
if (_i == 0)
{
return "0";
}
uint256 j = _i;
uint256 length;
while (j != 0)
{
length++;
j /= 10;
}
bytes memory bstr = new bytes(length);
uint256 k = length;
j = _i;
while (j != 0)
{
bstr[--k] = bytes1(uint8(48 + j % 10));
j /= 10;
}
str = string(bstr);
}
如果您需要选择性地转换为科学记数法,例如为了更紧凑的数字表示,这里有一个为此目的的修改版本:
function uintToString(uint v, bool scientific) public pure returns (string memory str) {
if (v == 0) {
return "0";
}
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(uint8(48 + remainder));
}
uint zeros = 0;
if (scientific) {
for (uint k = 0; k < i; k++) {
if (reversed[k] == '0') {
zeros++;
} else {
break;
}
}
}
uint len = i - (zeros > 2 ? zeros : 0);
bytes memory s = new bytes(len);
for (uint j = 0; j < len; j++) {
s[j] = reversed[i - j - 1];
}
str = string(s);
if (scientific && zeros > 2) {
str = string(abi.encodePacked(s, "e", uintToString(zeros, false)));
}
}
一些单元测试:
function testUintToString() public {
Assert.equal(Utils.uintToString(0, true), '0', '0');
Assert.equal(Utils.uintToString(1, true), '1', '1');
Assert.equal(Utils.uintToString(123, true), '123', '123');
Assert.equal(Utils.uintToString(107680546035, true), '107680546035', '107680546035');
Assert.equal(Utils.uintToString(1e9, true), '1e9', '1e9');
Assert.equal(Utils.uintToString(1 ether, true), '1e18', '1 ether');
Assert.equal(Utils.uintToString(550e8, true), '55e9', '55e9');
}
上面的代码片段与 solidity 兼容 0.6.0
。
solidity ^0.8.0
import "@openzeppelin/contracts/utils/Strings.sol";
Strings.toString(myUINT)
适合我。
虽然接受的答案似乎是正确的,但在处理大量问题时效率很低。以下是我的做法:
function itoa32 (uint x) private pure returns (uint y) {
unchecked {
require (x < 1e32);
y = 0x3030303030303030303030303030303030303030303030303030303030303030;
y += x % 10; x /= 10;
y += x % 10 << 8; x /= 10;
y += x % 10 << 16; x /= 10;
y += x % 10 << 24; x /= 10;
y += x % 10 << 32; x /= 10;
y += x % 10 << 40; x /= 10;
y += x % 10 << 48; x /= 10;
y += x % 10 << 56; x /= 10;
y += x % 10 << 64; x /= 10;
y += x % 10 << 72; x /= 10;
y += x % 10 << 80; x /= 10;
y += x % 10 << 88; x /= 10;
y += x % 10 << 96; x /= 10;
y += x % 10 << 104; x /= 10;
y += x % 10 << 112; x /= 10;
y += x % 10 << 120; x /= 10;
y += x % 10 << 128; x /= 10;
y += x % 10 << 136; x /= 10;
y += x % 10 << 144; x /= 10;
y += x % 10 << 152; x /= 10;
y += x % 10 << 160; x /= 10;
y += x % 10 << 168; x /= 10;
y += x % 10 << 176; x /= 10;
y += x % 10 << 184; x /= 10;
y += x % 10 << 192; x /= 10;
y += x % 10 << 200; x /= 10;
y += x % 10 << 208; x /= 10;
y += x % 10 << 216; x /= 10;
y += x % 10 << 224; x /= 10;
y += x % 10 << 232; x /= 10;
y += x % 10 << 240; x /= 10;
y += x % 10 << 248;
}
}
function itoa (uint x) internal pure returns (string memory s) {
unchecked {
if (x == 0) return "0";
else {
uint c1 = itoa32 (x % 1e32);
x /= 1e32;
if (x == 0) s = string (abi.encode (c1));
else {
uint c2 = itoa32 (x % 1e32);
x /= 1e32;
if (x == 0) {
s = string (abi.encode (c2, c1));
c1 = c2;
} else {
uint c3 = itoa32 (x);
s = string (abi.encode (c3, c2, c1));
c1 = c3;
}
}
uint z = 0;
if (c1 >> 128 == 0x30303030303030303030303030303030) { c1 <<= 128; z += 16; }
if (c1 >> 192 == 0x3030303030303030) { c1 <<= 64; z += 8; }
if (c1 >> 224 == 0x30303030) { c1 <<= 32; z += 4; }
if (c1 >> 240 == 0x3030) { c1 <<= 16; z += 2; }
if (c1 >> 248 == 0x30) { z += 1; }
assembly {
let l := mload (s)
s := add (s, z)
mstore (s, sub (l, z))
}
}
}
}
说明
itoa32
函数将小于 10^32 的数字转换为 32 位数字,必要时用零填充。
itoa
函数最多调用 itoa32
三次以转换任意 256 位数字,然后连接结果并删除前导零。它使用二进制搜索找出要删除的前导零的确切数量,并从字符串 in-place.
中删除前导零
在 Solidity 中,有没有办法将我的 int 转换为字符串?
示例:
pragma solidity ^0.4.4;
contract someContract {
uint i;
function test() pure returns (string) {
return "Here and Now is Happiness!";
}
function love() pure returns(string) {
i = i +1;
return "I love " + functionname(i) + " persons" ;
}
}
函数名是什么?谢谢!
这里的两位post给出了回复:
https://ethereum.stackexchange.com/questions/10811/solidity-concatenate-uint-into-a-string
https://ethereum.stackexchange.com/questions/10932/how-to-convert-string-to-int
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);
}
此致
已接受答案的评论中建议的 provable-things 代码对我有用,但我的 linter 发出了警告,即:"uintToStr": Avoid assigning to function parameters. [security/no-assign-params]
。下面稍微更改原始代码以更正此问题(将参数 _i
重新分配给另一个名为 number
的变量):
/// @notice converts number to string
/// @dev source: https://github.com/provable-things/ethereum-api/blob/master/oraclizeAPI_0.5.sol#L1045
/// @param _i integer to convert
/// @return _uintAsString
function uintToStr(uint _i) internal pure returns (string memory _uintAsString) {
uint number = _i;
if (number == 0) {
return "0";
}
uint j = number;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (number != 0) {
bstr[k--] = byte(uint8(48 + number % 10));
number /= 10;
}
return string(bstr);
}
Solidity 0.8.0 更新:
https://github.com/provable-things/ethereum-api/blob/master/provableAPI_0.6.sol 中的 uint2str()
函数现已过时,无法使用,但这是使用 solidity 0.8.0 的更新代码:
(在上一个版本中有一个溢出错误,但 solidity <0.8.0 忽略了它,因为它不影响答案,但现在会抛出错误)
byte
也更改为 bytes1
和 +、-、* 等等,就像它们在 SafeMath 库中一样。
function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len;
while (_i != 0) {
k = k-1;
uint8 temp = (48 + uint8(_i - _i / 10 * 10));
bytes1 b1 = bytes1(temp);
bstr[k] = b1;
_i /= 10;
}
return string(bstr);
}
Concrete_Buddhas 答案在 solidity 0.8.0 中不起作用。这是修订版:
function uint2str(
uint256 _i
)
internal
pure
returns (string memory str)
{
if (_i == 0)
{
return "0";
}
uint256 j = _i;
uint256 length;
while (j != 0)
{
length++;
j /= 10;
}
bytes memory bstr = new bytes(length);
uint256 k = length;
j = _i;
while (j != 0)
{
bstr[--k] = bytes1(uint8(48 + j % 10));
j /= 10;
}
str = string(bstr);
}
如果您需要选择性地转换为科学记数法,例如为了更紧凑的数字表示,这里有一个为此目的的修改版本:
function uintToString(uint v, bool scientific) public pure returns (string memory str) {
if (v == 0) {
return "0";
}
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(uint8(48 + remainder));
}
uint zeros = 0;
if (scientific) {
for (uint k = 0; k < i; k++) {
if (reversed[k] == '0') {
zeros++;
} else {
break;
}
}
}
uint len = i - (zeros > 2 ? zeros : 0);
bytes memory s = new bytes(len);
for (uint j = 0; j < len; j++) {
s[j] = reversed[i - j - 1];
}
str = string(s);
if (scientific && zeros > 2) {
str = string(abi.encodePacked(s, "e", uintToString(zeros, false)));
}
}
一些单元测试:
function testUintToString() public {
Assert.equal(Utils.uintToString(0, true), '0', '0');
Assert.equal(Utils.uintToString(1, true), '1', '1');
Assert.equal(Utils.uintToString(123, true), '123', '123');
Assert.equal(Utils.uintToString(107680546035, true), '107680546035', '107680546035');
Assert.equal(Utils.uintToString(1e9, true), '1e9', '1e9');
Assert.equal(Utils.uintToString(1 ether, true), '1e18', '1 ether');
Assert.equal(Utils.uintToString(550e8, true), '55e9', '55e9');
}
上面的代码片段与 solidity 兼容 0.6.0
。
solidity ^0.8.0
import "@openzeppelin/contracts/utils/Strings.sol";
Strings.toString(myUINT)
适合我。
虽然接受的答案似乎是正确的,但在处理大量问题时效率很低。以下是我的做法:
function itoa32 (uint x) private pure returns (uint y) {
unchecked {
require (x < 1e32);
y = 0x3030303030303030303030303030303030303030303030303030303030303030;
y += x % 10; x /= 10;
y += x % 10 << 8; x /= 10;
y += x % 10 << 16; x /= 10;
y += x % 10 << 24; x /= 10;
y += x % 10 << 32; x /= 10;
y += x % 10 << 40; x /= 10;
y += x % 10 << 48; x /= 10;
y += x % 10 << 56; x /= 10;
y += x % 10 << 64; x /= 10;
y += x % 10 << 72; x /= 10;
y += x % 10 << 80; x /= 10;
y += x % 10 << 88; x /= 10;
y += x % 10 << 96; x /= 10;
y += x % 10 << 104; x /= 10;
y += x % 10 << 112; x /= 10;
y += x % 10 << 120; x /= 10;
y += x % 10 << 128; x /= 10;
y += x % 10 << 136; x /= 10;
y += x % 10 << 144; x /= 10;
y += x % 10 << 152; x /= 10;
y += x % 10 << 160; x /= 10;
y += x % 10 << 168; x /= 10;
y += x % 10 << 176; x /= 10;
y += x % 10 << 184; x /= 10;
y += x % 10 << 192; x /= 10;
y += x % 10 << 200; x /= 10;
y += x % 10 << 208; x /= 10;
y += x % 10 << 216; x /= 10;
y += x % 10 << 224; x /= 10;
y += x % 10 << 232; x /= 10;
y += x % 10 << 240; x /= 10;
y += x % 10 << 248;
}
}
function itoa (uint x) internal pure returns (string memory s) {
unchecked {
if (x == 0) return "0";
else {
uint c1 = itoa32 (x % 1e32);
x /= 1e32;
if (x == 0) s = string (abi.encode (c1));
else {
uint c2 = itoa32 (x % 1e32);
x /= 1e32;
if (x == 0) {
s = string (abi.encode (c2, c1));
c1 = c2;
} else {
uint c3 = itoa32 (x);
s = string (abi.encode (c3, c2, c1));
c1 = c3;
}
}
uint z = 0;
if (c1 >> 128 == 0x30303030303030303030303030303030) { c1 <<= 128; z += 16; }
if (c1 >> 192 == 0x3030303030303030) { c1 <<= 64; z += 8; }
if (c1 >> 224 == 0x30303030) { c1 <<= 32; z += 4; }
if (c1 >> 240 == 0x3030) { c1 <<= 16; z += 2; }
if (c1 >> 248 == 0x30) { z += 1; }
assembly {
let l := mload (s)
s := add (s, z)
mstore (s, sub (l, z))
}
}
}
}
说明
itoa32
函数将小于 10^32 的数字转换为 32 位数字,必要时用零填充。
itoa
函数最多调用 itoa32
三次以转换任意 256 位数字,然后连接结果并删除前导零。它使用二进制搜索找出要删除的前导零的确切数量,并从字符串 in-place.