Solidity对string拓展类库

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();
    }
    
}  
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值