@IsFullWidth, @IsHalfWidth

В текстовых данных, особенно при работе с восточноазиатскими языками, символы могут существовать в двух визуально и семантически различающихся формах: fullwidth (полная ширина) и halfwidth (половинная ширина). Эти формы отличаются не только отображением, но и кодировкой в Unicode.

Символы полной ширины занимают фиксированное пространство, эквивалентное ширине иероглифа. Символы половинной ширины визуально сжаты и чаще встречаются в латинском алфавите, цифрах и базовой пунктуации.

Валидационные декораторы class-validator позволяют проверять соответствие строк этим правилам:

  • @IsFullWidth() — строка должна содержать только символы полной ширины
  • @IsHalfWidth() — строка должна содержать только символы половинной ширины

@IsFullWidth: проверка символов полной ширины

Логика работы

Декоратор @IsFullWidth() проверяет, что все символы строки относятся к Unicode-блокам полной ширины. К таким символам относятся:

  • CJK иероглифы
  • символы катаканы полной ширины
  • полноширинные формы латиницы и цифр
  • знаки пунктуации в fullwidth-варианте

Внутренняя проверка обычно основана на регулярных выражениях, охватывающих диапазоны Unicode, например:

  • \uFF01–\uFF60 — полноширинные ASCII-аналоги
  • \uFFE0–\uFFE6 — дополнительные символы валют и пунктуации
  • диапазоны CJK Unified Ideographs

Базовое использование

import { IsFullWidth } from 'class-validator';

class CreateMessageDto {
  @IsFullWidth()
  content: string;
}

В этом случае строка content должна состоять исключительно из символов полной ширины.


Примеры валидных значений

Hello World
123456
コンニチハ
你好世界

Все эти строки используют fullwidth-символы или иероглифы.


Примеры невалидных значений

Hello World
123456
Hello World (смешанный набор)

Любой ASCII-символ в половинной ширине делает строку невалидной.


Практическое применение

@IsFullWidth() используется в системах, где требуется строгое соответствие визуальному формату:

  • японские формы ввода
  • банковские системы, работающие с legacy-форматами
  • базы данных, чувствительные к ширине символов
  • печатные шаблоны документов

@IsHalfWidth: проверка символов половинной ширины

Логика работы

Декоратор @IsHalfWidth() ограничивает строку только символами половинной ширины. Проверка исключает:

  • иероглифы CJK
  • fullwidth-латиницу
  • fullwidth-цифры
  • большинство восточноазиатских символов

Разрешены:

  • ASCII-латиница
  • цифры 0–9
  • базовая пунктуация
  • катакана половинной ширины (halfwidth katakana block)

Базовое использование

import { IsHalfWidth } from 'class-validator';

class LoginDto {
  @IsHalfWidth()
  username: string;
}

Примеры валидных значений

HelloWorld
user123
ハンカクカタカナ
email@example.com

Примеры невалидных значений

Hello
12345
こんにちは

Любой символ полной ширины нарушает правило.


Отличия @IsFullWidth и @IsHalfWidth

Семантика проверки

Декоратор Допустимые символы Основная область применения
@IsFullWidth() Только fullwidth/ideographs Формы CJK, строгие шаблоны
@IsHalfWidth() Только ASCII/halfwidth Логины, email-подобные поля

Поведение при смешанных строках

Оба декоратора работают по принципу строгой проверки всей строки:

  • наличие одного символа “чужого” типа делает строку невалидной
  • частичное соответствие не допускается

Unicode-основы различий ширины

Fullwidth

Fullwidth-символы разработаны для унификации визуального представления в вертикальных и моноширинных системах отображения. Они:

  • занимают фиксированную ширину, равную CJK-символам
  • имеют отдельные кодовые точки в Unicode
  • часто используются в японской и китайской типографике

Примеры:

  • A (U+FF21)
  • 1 (U+FF11)
  • ! (U+FF01)

Halfwidth

Halfwidth-форма представляет собой компактный вариант символов:

  • используется в ASCII-ориентированных системах
  • оптимизирована для плотного текста
  • поддерживает совместимость с западными кодировками

Примеры:

  • A (U+0041)
  • 1 (U+0031)
  • ! (U+0021)

Поведение валидации в class-validator

Общие принципы

Оба декоратора:

  • работают на уровне строки
  • игнорируют типизацию на уровне символов, но валидируют каждый символ
  • возвращают ошибку при первом несоответствии или после полной проверки (в зависимости от настроек пайплайна)

Сообщения об ошибках

По умолчанию библиотека генерирует стандартные сообщения:

  • @IsFullWidth() → “must contain full-width characters”
  • @IsHalfWidth() → “must contain half-width characters”

Сообщения могут быть переопределены:

@IsFullWidth({ message: 'Поле должно содержать символы полной ширины' })
content: string;

Использование в DTO (Data Transfer Objects)

В контексте NestJS DTO часто комбинируются с другими валидаторами:

import { IsString, Length } from 'class-validator';
import { IsHalfWidth } from 'class-validator';

class UserDto {
  @IsString()
  @IsHalfWidth()
  @Length(3, 20)
  username: string;
}

Такой подход позволяет одновременно:

  • ограничивать тип данных
  • проверять формат символов
  • контролировать длину строки

Сценарии ошибок и нюансы

Смешанные Unicode-строки

Строка может выглядеть одинаково визуально, но содержать разные кодовые точки:

A (U+0041) ≠ A (U+FF21)

Это критично при:

  • поиске в базе данных
  • сравнении строк
  • нормализации пользовательского ввода

Нормализация данных

Перед применением валидации иногда требуется нормализация:

  • NFC / NFKC формы Unicode
  • приведение fullwidth → halfwidth (или наоборот)

Однако class-validator не выполняет автоматическую нормализацию, проверка осуществляется “как есть”.


Катакана halfwidth

Отдельный случай — японская halfwidth катакана:

ハンカク

Она проходит @IsHalfWidth(), но не проходит @IsFullWidth().


Взаимодействие с другими валидаторами

Обычно эти декораторы используются вместе с:

  • @IsString() — проверка типа
  • @Matches() — дополнительные регулярные ограничения
  • @Length() — контроль размера строки
  • @IsNotEmpty() — запрет пустых значений

Комбинация позволяет строить строгие правила ввода для интернациональных систем.


Типичные ошибки при использовании

  • ожидание частичного соответствия (декораторы не работают по принципу “разрешить хотя бы часть”)
  • игнорирование нормализации Unicode
  • смешивание fullwidth и halfwidth в одной строке
  • применение к свободному пользовательскому вводу без учёта локализации интерфейса