← Статьи

Разделитель GS в кодах GS1: что это и где он теряется

GS — невидимый символ с кодом 29, который показывает, где заканчивается поле переменной длины. Без него строка кода не разбирается на поля, и касса или учётная система отклоняет код, хотя сам DataMatrix читается идеально.

Зачем нужен разделитель

В коде GS1 поля идут подряд, без пробелов: сначала две-четыре цифры идентификатора применения (AI), потом значение. У части AI длина задана стандартом — например, GTIN в поле 01 всегда 14 цифр, и парсер знает, где он кончится. У других длина переменная: серийный номер 21 может быть до 20 символов, и без разделителя не понять, где он кончается и начинается следующее поле.

Правило: после каждого поля переменной длины ставится разделитель, если за ним идёт ещё поле. После последнего поля разделитель не нужен.

[FNC1] 01 04601234567893  21 5Ab3dE7fGh9kL [GS]  91 EE10 [GS]  92 <44 символа>
       └ фикс. 14 цифр ┘  └ переменная ┘        └перем.┘       └ последнее поле — без GS

В кодах «Честного знака» это даёт две типичные схемы:

СтруктураГде стоит GS
01 + 21 + 91 + 92 (длинный код)После серийного номера и после ключа 91
01 + 21 + 93 (короткий код)Только после серийного номера
01 + 21 + 93 + 3103 (молоко с весом)После серийного номера и после кода проверки 93

Источники: состав кода для БАД и молочной продукции на сайте оператора.

FNC1 и GS — в чём разница

Внутри символа DataMatrix есть специальный кодовый символ FNC1 (кодовое слово 232). Он работает дважды:

  • В начале кода FNC1 объявляет символ кодом GS1. Сканер его не передаёт, а при включённом префиксе символогии начинает строку с ]d2 вместо ]d1 у обычного DataMatrix.
  • В середине кода FNC1 — разделитель полей, и сканер передаёт его как символ GS, ASCII 29 (Packaging Digest).

Некоторые программы печати кодируют в середине не FNC1, а сам символ GS. Сканер в обоих случаях выдаст одну и ту же строку, но верификатор качества может отметить это как отклонение от GS1. А вот ведущий FNC1 заменить нечем: без него код — обычный DataMatrix, и касса его не примет.

Где GS теряется

Разделитель — управляющий символ, и его тихо вырезает любое звено, которое считает его мусором:

ЗвеноЧто происходитЧто делать
Сканер в режиме эмуляции клавиатурыGS передаётся как сочетание клавиш, которое программа игнорирует или понимает по-своемуПеревести сканер в режим виртуального COM-порта или настроить замену GS на печатный символ, который программа вернёт обратно
CSV, Excel, буфер обменаУправляющие символы вырезаются при импорте и копированииХранить коды в файлах как получено от оператора и не прогонять через Excel
Шаблон этикеткиВ данные попадает не символ, а текст «\x1d» или «<GS>»Использовать способ ввода FNC1, предусмотренный вашей программой печати
Декодер без поддержки GS1Ведущий FNC1 теряется или приходит как непечатный символПроверять префикс ]d2 или флаг GS1 в API декодера
Веб-формы и JSONПоле очищается от «невидимых» символовПередавать как \u001d в JSON и не делать trim по управляющим символам

Ошибаются и сами декодеры. При сверке нашего декодера с ГОСТ Р ИСО/МЭК 16022 нашлась именно такая ошибка: FNC1 дальше второй позиции терялся, а не передавался как GS. На экране такой код выглядит нормально, и заметить потерю можно только по байтам.

Как проверить, что GS на месте

Самый надёжный способ — посмотреть байты, а не текст на экране. В шестнадцатеричном виде GS — это 1d:

code = scanner.read()            # строка от сканера или декодера
print(code.encode("latin-1").hex(" "))
# ... 4c 1d 39 31 ...  — 1d после серийного номера, перед "91"
assert "\x1d" in code, "разделитель потерян"

Если 1d нет ни в одной точке, идите по цепочке от сканера к базе данных и смотрите, на каком шаге он исчезает. Если его нет уже на выходе сканера — проблема в напечатанном коде или настройках сканера.

Попробовать

Генератор libscanner формирует GS1 DataMatrix с ведущим FNC1 и разделителями в нужных местах; попробовать можно в онлайн-генераторе на сайте, исходники — на GitHub.

Ридер бережёт разделитель на всех выходах: в Python Code.text — bytes, и GS остаётся байтом 0x1D; командная строка dmr печатает его как <GS>, чтобы он не потерялся при копировании. Настройка requireGs1 отсекает коды без структуры GS1. Установка — pip install libscanner-dmr, проверка по фото — онлайн-сканер.

«Честный знак» — товарный знак ООО «Оператор-ЦРПТ», «GS1» — GS1 AISBL; продукт не связан с их владельцами и ими не сертифицирован.