Solidity对string拓展类库
Solidity 语言本身提供的string
功能比较弱,并没有提供一些实用函数,我们可以写一些类库拓展string
类型。
以下是个人拓展string
类型的操作,有些不妥当的地方望多多包涵。
StringUtils.sol代码
pragma solidity >=0.6.10 <0.8.20;
library StringUtils {
string internal constant EMPTY_STRING = "";
/**
* @notice 获取字符串长度
* @dev 不支持中文字符串,bytes(str)是获取对应str的UTF-8编码,每个中文UTF-8编码字符长度为3。
* @param str 字符串
* @return 字符串长度
*/
function length(string memory str)
internal pure
returns (uint256)
{
return bytes(str).length;
}
/**
* @notice 判断字符串为空
* @param str 字符串
* @return 是否为空
*/
function isBlank(string memory str)
internal pure
returns (bool)
{
return length(str) == 0;
}
/**
* @notice 判断字符串不为空
* @param str 字符串
* @return 是否不为空
*/
function isNotBlank(string memory str)
internal pure
returns (bool)
{
return !isBlank(str);
}
/**
* @notice 判断字符串是否相等
* @param str1 字符串1
* @param str2 字符串2
* @return 是否相等
*/
function equal(string memory str1, string memory str2)
internal pure
returns (bool)
{
return length(str1) == length(str2) && keccak256(bytes(str1)) == keccak256(bytes(str2));
}
/**
* @notice 判断字符串是否以前缀开头
* @dev 不支持中文字符串,bytes(str)是获取对应str的UTF-8编码
* @param str1 原始字符串
* @param str2 查询字符串
* @return 是否以前缀开头
*/
function startsWith(string memory str1, string memory str2)
internal pure
returns (bool)
{
bytes memory searchStrBytes = bytes(str1);
bytes memory prefixStrBytes = bytes(str2);
if (searchStrBytes.length < prefixStrBytes.length) {
return false;
}
bytes memory strBytes = new bytes(prefixStrBytes.length);
for (uint i = 0; i < prefixStrBytes.length; i++) {
strBytes[i] = searchStrBytes[i];
}
return keccak256(strBytes) == keccak256(prefixStrBytes);
}
/**
* @notice 两个字符串拼接
* @param str1 字符串1
* @param str2 字符串2
* @return 拼接后字符串
*/
function contact(string memory str1, string memory str2)
internal pure
returns (string memory)
{
return string(abi.encodePacked(str1, str2));
}
/**
* @notice 字符串截取
* @dev 不支持中文字符串,bytes(str)是获取对应str的UTF-8编码
* @dev 截取字符串包含start索引
* @param str 字符串
* @param start 开始索引
* @return 截取后的字符串
*/
function substring(string memory str, uint256 start)
internal pure
returns (string memory)
{
uint256 strLength = length(str);
if (start >= strLength) {
return EMPTY_STRING;
}
bytes memory strBytes = bytes(str);
bytes memory newStrBytes = new bytes(strLength - start);
for (uint256 i = 0; i < (strLength - start); i++) {
newStrBytes[i] = strBytes[start + i];
}
return string(newStrBytes);
}
/**
* @notice 字符串截取
* @dev 不支持中文字符串,bytes(str)是获取对应str的UTF-8编码
* @dev 截取字符串包含start索引,不包含end索引
* @param str 字符串
* @param start 开始索引
* @param end 结束索引
* @return 截取后的字符串
*/
function substring(string memory str, uint256 start, uint256 end)
internal pure
returns (string memory)
{
if (start > end) {
return EMPTY_STRING;
}
uint256 strLength = length(str);
if (start >= strLength) {
return EMPTY_STRING;
}
if (end > strLength) {
end = strLength;
}
bytes memory strBytes = bytes(str);
bytes memory newStrBytes = new bytes(end - start);
for (uint256 i = 0; i < (end - start); i++) {
newStrBytes[i] = strBytes[start + i];
}
return string(newStrBytes);
}
/**
* @notice 判断字符串的索引
* @dev 不支持中文字符串,bytes(str)是获取对应str的UTF-8编码
* @dev 原始字符串没有匹配查询字符串时返回-1
* @param str1 原始字符串
* @param str2 查询字符串
* @return 索引
*/
function indexOf(string memory str1, string memory str2)
internal pure
returns (int256)
{
bytes memory str1Bytes = bytes(str1);
bytes memory str2Bytes = bytes(str2);
uint256 str1Length = str1Bytes.length;
uint256 str2Length = str2Bytes.length;
if (str1Length < 1 || str2Length < 1 || (str2Length > str1Length)) {
return - 1;
} else if (str1Length > (2 ** 128 - 1)) {
return - 1;
} else {
uint256 subIndex = 0;
for (uint256 i = 0; i < str1Length; i ++) {
if (str1Bytes[i] == str2Bytes[0]) {
subIndex = 1;
while (subIndex < str2Length && (i + subIndex) < str1Length && str1Bytes[i + subIndex] == str2Bytes[subIndex]) {
subIndex++;
}
if (subIndex == str2Length) {
return int256(i);
}
}
}
return - 1;
}
}
/**
* @notice 将无符号数字字符串转成无符号数字
* @dev 非无符号数字的字符串转换结果都为0 eg: "ab","a1b","-123" -> 0
* @param str 字符串
* @return 无符号数字
*/
function stringToUint256(string memory str)
internal pure
returns (uint256) {
uint256 result = 0;
bytes memory strBytes = bytes(str);
uint256 strLength = strBytes.length;
for (uint256 i = 0; i < strLength; i++) {
if (uint8(strBytes[i]) >= 48 && uint8(strBytes[i]) <= 57) {
result = result * 10 + (uint8(strBytes[i]) - 48);
} else {
return 0;
}
}
return result;
}
}
合约中使用StringUtils类库
静态用法
以length
方法为例
import "./StringUtils.sol";
contract StringUtilsTest {
function length(string memory str)
public pure
returns (uint256)
{
return StringUtils.length(str);
}
}
拓展用法
以length
方法为例
import "./StringUtils.sol";
contract StringUtilsTest {
//使用StringUtils拓展string
using StringUtils for string;
function length(string memory str)
public pure
returns (uint256)
{
return str.length();
}
}