Найдите длину любой строки в 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).
Оригинал