Solidity兩個string的比較
有三種比較方法
方法一:比較string的雜湊值
方法二:先比較string的長度,再比較每個對應位置的字母是否相同
方法三:先比較string的長度,再比較string的雜湊值
一.比較string的雜湊值
function hashCompareInternal(string a, string b) internal returns (bool) { return keccak256(a) == keccak256(b); }
二.先比較string的長度,再比較每個對應位置的字母是否相同
function utilCompareInternal(string a, string b) internal returns (bool) {if (bytes(a).length != bytes(b).length) { return false; } for (uint i = 0; i < bytes(a).length; i ++) { if(bytes(a)[i] != bytes(b)[i]) { return false; } } return true; }
三.先比較string的長度,再比較string的雜湊值
function hashCompareWithLengthCheckInternal(string a, string b) internal returns (bool) {if (bytes(a).length != bytes(b).length) { return false; } else { return keccak256(a) == keccak256(b); } }
四.三種比較方法的gas分析
在remix上執行也可以看到gas情況,但感覺不準,這裡的統計參考:https://blog.csdn.net/xiaomei1xiake2/article/details/81868317
由以上的測試可知:
1.當超過兩個字母需要比較的時候,雜湊方法(方法一和方法三)消耗的gas比較少;
2.當這兩個string的長度不同時,先進行長度比較(方法二和方法三)可以節省將近40%的gas。
3.先進行長度比較只是多花了3%的gas,但可能可以節省40%的gas。
4.與使用字母比較(方法二)的方法相比,使用雜湊方法(方法一和方法三)gas的消耗比較穩定。使用字母比較的方法消耗gas的數量呈線性增長。
五.在實際應用中,可以AOP方式,也可以在函式中直接判斷
pragma solidity ^0.4.24; contract StringComp { mapping (address => bool) public compareRecord; bool public checkResult = false; modifier check(string _str1,string _str2) { require(keccak256(abi.encodePacked(_str1)) == keccak256(abi.encodePacked(_str2))); _; } // 使用AOP方式check比較兩個字串 function func1 (string __str1, string __str2) public check(__str1,__str2) returns(bool) { // 儲存呼叫者的比較結果 compareRecord[msg.sender] = true; } // 函式中直接判斷 function compareStr (string _str1, string _str2) public returns(bool) { if(keccak256(abi.encodePacked(_str1)) == keccak256(abi.encodePacked(_str2))) { // 如果二者相等,使checkResult為true checkResult = true; }else { checkResult = false; } // 返回checkResult return checkResult; } }
在這裡,有直接用abi.encodePacked進行打包,關於abi.encodePacked方法說明,詳見如下:
詳見:https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html
五.特別說明
keccak256方法在0.4.2及其下版本不支援,至少需0.4.3版本。
附:在remix上執行截圖
1.StrComp.sol
pragma solidity ^0.4.24; contract StrComp { function hashCompareInternal(string a, string b) public returns (bool) { return keccak256(a) == keccak256(b); } function utilCompareInternal(string a, string b) public returns (bool) { if (bytes(a).length != bytes(b).length) { return false; } for (uint i = 0; i < bytes(a).length; i ++) { if(bytes(a)[i] != bytes(b)[i]) { return false; } } return true; } function hashCompareWithLengthCheckInternal(string a, string b) public returns (bool) { if (bytes(a).length != bytes(b).length) { return false; } else { return keccak256(a) == keccak256(b); } } }
2.StringComp.sol
pragma solidity ^0.4.24; contract StringComp { mapping (address => bool) public compareRecord; bool public checkResult = false; modifier check(string _str1,string _str2) { require(keccak256(abi.encodePacked(_str1)) == keccak256(abi.encodePacked(_str2))); _; } // 使用AOP方式check比較兩個字串 function func1 (string __str1, string __str2) public check(__str1,__str2) returns(bool) { // 儲存呼叫者的比較結果 compareRecord[msg.sender] = true; } // 函式中直接判斷 function compareStr (string _str1, string _str2) public returns(bool) { if(keccak256(abi.encodePacked(_str1)) == keccak256(abi.encodePacked(_str2))) { // 如果二者相等,使checkResult為true checkResult = true; }else { checkResult = false; } // 返回checkResult return checkResult; } }
參考文章:https://blog.csdn.net/xiaomei1xiake2/article/details/81868317
https://www.liankexing.com/index.php/Question/question_page.html?id=1249
https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html
remix地址:https://remix.ethereum.org/