Найдите длину любой строки в Solidity

Найдите длину любой строки в Solidity

1 июня 2022 г.

Почему bytes(str).length недостаточно для получения длины строки в Solidity и понимания метода strlen из контрактов ens.


В мире Javascript найти длину строки очень просто. Просто сделайте str.length и все 🤌


Но со строками не так удобно работать в Solidity ❗. В твердости строка представляет собой группу символов, хранящихся внутри массива, и хранит данные в байтах.


В строковом типе нет метода длины.


Я просматривал проект build-polygon-ens от Buildspace и нашел ссылку на StringUtils.sol. Я знал, что для нахождения длины строки в Solidity мы можем преобразовать строку в байты и найти ее длину. Таким образом, это должно было быть так же просто, как выполнить bytes(str).length;🤌, но метод в этом файле утилиты был немного другим:


```javascript


// SPDX-идентификатор лицензии: MIT


// Источник:


// https://github.com/ensdomains/ens-contracts/blob/master/contracts/ethregistrar/StringUtils.sol


прочность прагмы >=0,8,4;


библиотека StringUtils {


  • @dev Возвращает длину заданной строки

  • @param s Строка для измерения длины

  • @return Длина входной строки

функция strlen(string memory s) внутренние чистые возвраты (uint256) {


uint256 длина;


uint256 я = 0;


uint256 длина байта = байты(ы).длина;


for (len = 0; i < длина байта; len++) {


bytes1 b = байты(ы)[i];


если (б < 0x80) {


я += 1;


} иначе если (b < 0xE0) {


я += 2;


} иначе если (b < 0xF0) {


я += 3;


} иначе если (b < 0xF8) {


я += 4;


} иначе если (b < 0xFC) {


я += 5;


} еще {


я += 6;


вернуть лен;


В коде был странный цикл for, который я не мог понять.


Итак, разработчик во мне погуглил 🕵️‍♀️, но все статьи, которые мне попадались, делали это, чтобы найти длину строки bytes(str).length; я нашел похожий код на Stackoverflow, но никто на самом деле не объяснил, что происходит внутри.


```javascript


for(len = 0; i < длина байта; len++) {


bytes1 b = байты(ы)[i];


если (б < 0x80) {


я += 1;


} иначе если (b < 0xE0) {


я += 2;


} иначе если (b < 0xF0) {


я += 3;


} иначе если (b < 0xF8) {


я += 4;


} иначе если (b < 0xFC) {


я += 5;


} еще {


я += 6;


После 3 часов 🐌 самоисследования я смог разобраться сам (немного медленно, но у меня получилось 🍾),


Поэтому я подумал, давайте запишем это, чтобы это было полезно для всех людей, таких как я (не очень опытных в битах, байтах 0️⃣1️⃣).


Давайте попробуем разблокировать/декодировать это


Как работает bytes(str).length


Когда мы конвертируем строку в байты, вот что делает Solidity:


```javascript


// если мы делаем bytes("xyz"), Solidity преобразует их как


xyz -> 78 79 7a // 78=x, 79=y, 7a=z


ABC -> 41 42 43 // 41=А, 42=В, 43=С


Используйте этот веб-сайт для преобразования строк в байты


Если вы видите, что каждый символ генерирует 1 байт, поэтому, когда мы делаем bytes(””).length, мы получаем длину строки. Но есть некоторые символы, для которых сгенерированных байтов больше одного. Например:


```javascript


€ -> e2 82 ак


Для символа евро сгенерировано 3 байта.



Итак, если мы попытаемся найти длину строки, которая включает в себя символ евро() 🤑, длина, возвращаемая bytes(str).length, не вернет правильную длину строки для этот символ как  генерируется 3 байта:



Вот когда это «для» петля, которую мы видели выше, приходит на помощь ⛑️


Давайте повторим это e2 82 ac


bytes и проверьте, что происходит внутри этого цикла:


```javascript


for(len = 0; i < длина байта; len++) {


bytes1 b = байты(ы)[i];


// b = e2 для первой итерации


если (б < 0x80) {


я += 1;


} иначе если (b < 0xE0) {


я += 2;


} иначе если (b < 0xF0) {


я += 3;


} иначе если (b < 0xF8) {


я += 4;


} иначе если (b < 0xFC) {


я += 5;


} еще {


я += 6;


Для первой итерации b=e2в следующей строке есть условие


```javascript


если (б < 0x80) {


я += 1;


Давайте расшифруем это. Это условие будет в основном сравнивать десятичные значения этих шестнадцатеричных символов:


```javascript


0x80 -> 128


// наш b на данный момент равен e2, десятичное значение для e2 = 226


0xe2 -> 226


Для обычных символов десятичное преобразование их шестнадцатеричного символа будет < 128 , например, для a это 97.


Итак, если мы проверим все условия, как это


```javascript


for(len = 0; i < длина байта; len++) {


bytes1 b = байты(ы)[i];


if(b < 0x80) { //0x80 = 128 => 226 < 128 ❌


я += 1;


} else if (b < 0xE0) { //0xE0 = 224 => 226 < 224 ❌


я += 2;


} else if (b < 0xF0) { //0xF0 = 240 => 226 < 240 ✅


я += 3;


Таким образом, если наше i равно 3, условие в цикле for будет равно 3<3, что ложно, и цикл прервется, а значение len в данный момент будет равно 1.


Вот и все, это правильное значение длины строки «»


Если вы хотите попробовать еще несколько строк, таких как «», вот небольшой список символов, занимающих более 1 байта:


```javascript


€ -> e2 82 ак


М -> с3 83


¢ -> с2 а2


Создайте случайную строку, например, abc¢Ã, и попробуйте.


Та-Да 🎉, и теперь это работает



Свяжитесь со мной в Twitter@pateldeep_eth или LinkedIn


Мои личные сообщения открыты для любых улучшений или предложений


Первоначально опубликовано [здесь] (https://pateldeep.xyz/blog/how-to-find-length-of-string-in-solidity-%E2%80%94-from-the-smart-contract- of-%E2%80%9Cens%E2%80%9D).



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE