Этот пост родился из-за странного поведения валидатора Length
из пакета ozzo-validation.
Следуя руководству, можно зарегистрировать, например, такой валидатор для строк:
data := "Некоторая строка"
err := validation.Validate(data,
validation.Required,
validation.Length(10, 16),
)
fmt.Println(err)
И так как в строке у нас кириллические символы, и более того - кодировка строки utf-8, то валидация не пропускает строку, падая с ошибкой "the length must be between 10 and 16". Почему так происходит, ведь валидируемая строка содержит ровно 16 символов?
Для того, чтобы понять почему валидация выдает ошибку - придется сходить в исходный код валидатора. Поиски приводят к тому, что для определения длины валидируемой строки используется метод Len()
из типа reflect#Value
. Путешествие дальше приводит нас к тому, что свойство Len
вычисляется с помощью встроенной функции len
. А как сообщает мануал:
The len built-in function returns the length of v, according to its type:
String: the number of bytes in v.
Следовательно, валидация на основании длины строки в байтах нас не устраивает, так как в случае многобайтных кодировок (коей является utf-8) число символов в строке не равно числу байт в этой же строке.
Хотелось бы, чтобы был метод типа utfLen()
. И он есть в пакете unicode/utf8
, правда, с немного другим названием - RuneCountInString
. И о чудо, данный метод даже используется в валидаторе, если установить дополнительный флаг rune
. И это можно сделать применив валидатор RuneLength
.
Обновленный код:
data := "Некоторая строка"
err := validation.Validate(data,
validation.Required,
validation.RuneLength(10, 16),
)
fmt.Println(err)
Валидация отрабатывает как и ожидается, выводя <nil>
.
И не забудьте написать для этого случая тест (ну или хотя бы комментарий), чтобы пытливый программист, использующий код после вас, не смог бы заменить RuneLength
на Length
, думая, что "и так сойдёт".
P.S. Больше разъяснений про длины строк можно почитать в этом ответе на stackoverflow.
P.P.S. Отличное видео на Youtube, раскрывающее суть кодировок.
Комментариев нет:
Отправить комментарий