Строка без цифр и знаков: проверяем буквы во встроенном языке 1С 8.3

· 10 мин

Содержание

Чтобы проверить, что в строке только буквы, в 1С 8.3 перебирают символы циклом: Сред(Строка, Позиция, 1) берёт символ, СтрНайти(Алфавит, Символ) проверяет, есть ли он в списке допустимых. Нашли чужой символ — возвращаем Ложь. На платформе с номером не ниже 8.3.23 то же самое делается одной строкой через регулярное выражение СтрСоответствуетШаблону(Строка, "^[а-яА-ЯёЁ]+$").

Готовой функции «ТолькоБуквы» в платформе нет, как нет и такого типа значения. Самописные проверки чаще всего ломаются на букве «ё», дефисе в фамилии, неразрывном пробеле и латинице, замаскированной под кириллицу. Эти случаи стоит учесть сразу, а не после первой жалобы пользователя.

Перебор символов строки: базовая проверка через Сред и СтрНайти

Самый понятный способ. Работает на любой версии 8.3, в любом контексте: на клиенте, на сервере, в фоновом задании. Алфавит задаёте сами, поэтому точно знаете, что считается буквой.

// Возвращает Истина, если строка непустая и состоит только из русских букв.
Функция ТолькоРусскиеБуквы(Знач Строка) Экспорт

    Если ПустаяСтрока(Строка) Тогда
        Возврат Ложь;
    КонецЕсли;

    Алфавит = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
        + "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";

    Для Позиция = 1 По СтрДлина(Строка) Цикл
        Символ = Сред(Строка, Позиция, 1);
        Если СтрНайти(Алфавит, Символ) = 0 Тогда
            Возврат Ложь;
        КонецЕсли;
    КонецЦикла;

    Возврат Истина;

КонецФункции

Что здесь важно:

  • 🔹 ПустаяСтрока() возвращает Истина и для строки из одних пробелов. Без этой проверки пустое поле «пройдёт» как корректное: цикл не выполнится ни разу.
  • 🔹 СтрНайти() появилась в 8.3.6. На старых релизах её заменяет Найти() с тем же смыслом.
  • 🔹 Нужна латиница — допишите в Алфавит строки abc…z и ABC…Z. Нужен пробел или дефис — добавьте их туда же.

Выход из цикла по первому чужому символу — главная экономия. Для строки «Иванов1» функция проверит 7 символов, для «1Иванов» — один.

КодСимвола и диапазоны Юникода: проверка букв по коду

Второй вариант — сравнивать не символ, а его код. Функция КодСимвола(Строка, Позиция) возвращает код Юникода символа в указанной позиции. Дополнительная строка-алфавит не нужна.

Коды, которые пригодятся:

СимволыКодыПримечание
А–Я1040–1071без «Ё»
а–я1072–1103без «ё»
Ё1025вне основного диапазона
ё1105вне основного диапазона
A–Z65–90латиница, заглавные
a–z97–122латиница, строчные
Функция ЭтоКириллическаяБуква(Код)
    Возврат (Код >= 1040 И Код <= 1103) Или Код = 1025 Или Код = 1105;
КонецФункции

Функция ТолькоКириллица(Знач Строка) Экспорт

    Если ПустаяСтрока(Строка) Тогда
        Возврат Ложь;
    КонецЕсли;

    Для Позиция = 1 По СтрДлина(Строка) Цикл
        Если Не ЭтоКириллическаяБуква(КодСимвола(Строка, Позиция)) Тогда
            Возврат Ложь;
        КонецЕсли;
    КонецЦикла;

    Возврат Истина;

КонецФункции

Буквы «Ё» и «ё» стоят вне диапазона А–я. Если проверять только 1040–1103, фамилия «Королёв» не пройдёт проверку. Это самая частая ошибка в самописных функциях.

Приём с ВРег и НРег: буква любого алфавита

Если нужно принять буквы любого языка — русские, латинские, греческие, казахские — список кодов не нужен. У буквы есть заглавная и строчная форма, у цифры и знака препинания — нет:

Функция ЭтоБуква(Символ)
    Возврат ВРег(Символ) <> НРег(Символ);
КонецФункции

Для «Ж» ВРег даёт «Ж», НРег — «ж»: формы разные, значит, буква. Для «7» или «-» обе функции возвращают тот же символ.

Приём не распознаёт буквы письменностей без регистра (китайские иероглифы, арабское письмо). Для справочника контрагентов из России это не важно, для международных данных — учитывайте.

Регулярные выражения в 1С 8.3: короткая проверка шаблоном

Начиная с платформы 8.3.23 во встроенном языке есть функции для работы с регулярными выражениями. Для проверки «вся строка — буквы» достаточно одной:

ЭтоТолькоБуквы = СтрСоответствуетШаблону(Строка, "^[а-яА-ЯёЁ]+$");
  • ^ и $ — начало и конец строки: шаблон должен покрыть её целиком.
  • [а-яА-ЯёЁ] — допустимые символы, «ё» указана отдельно по той же причине, что и выше.
  • + — один символ или больше, поэтому пустая строка не пройдёт.

Варианты шаблонов под типовые задачи:

ЗадачаШаблон
Только русские буквы^[а-яА-ЯёЁ]+$
Только латиница^[a-zA-Z]+$
Русские и латинские буквы^[а-яА-ЯёЁa-zA-Z]+$
ФИО: буквы, пробел, дефис^[а-яА-ЯёЁ]+([ -][а-яА-ЯёЁ]+)*$

Последний шаблон пропускает «Римский-Корсаков Николай», но отсекает двойной пробел, дефис в начале и строку «- -».

Полный список функций для регулярных выражений смотрите в синтакс-помощнике конфигуратора: введите в поиск «РегулярномуВыражению». Если функция не находится, платформа ниже 8.3.23 или в свойствах конфигурации выставлен режим совместимости со старой версией.

Регулярные выражения через COM на старых платформах

До 8.3.23 разработчики пользовались COM-объектом Windows VBScript.RegExp:

&НаСервере
Функция ТолькоБуквыRegExp(Строка)
    RegExp = Новый COMОбъект("VBScript.RegExp");
    RegExp.Pattern = "^[а-яА-ЯёЁ]+$";
    RegExp.IgnoreCase = Ложь;
    Возврат RegExp.Test(Строка);
КонецФункции

Ограничения у способа серьёзные:

  • 🚫 работает только там, где код выполняется под Windows. Сервер 1С на Linux, веб-клиент и мобильное приложение его не поддерживают;
  • 🚫 создание COM-объекта медленное, в цикле по тысячам строк создавайте его один раз, а не на каждой итерации;
  • 🚫 Microsoft объявила VBScript устаревшим компонентом, на новых сборках Windows он может быть отключён.

Ещё один старый обходной путь — тип XDTO с ограничением pattern из XML-схемы. Он кроссплатформенный, но громоздкий: схему приходится собирать текстом. Сейчас его есть смысл держать только в коде, который обязан работать на платформах ниже 8.3.23.

Готовой функции «только буквы» нет: что выбрать вместо неё

Встроенного метода вроде ЭтоБуква() или типа значения с ограничением «только буквы» в платформе нет. Описание типов Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(50)) ограничивает только длину строки, состав символов оно не контролирует.

Есть похожая функция СтрокаСостоитИзЦифр() — но не в платформе, а в Библиотеке стандартных подсистем (модуль СтроковыеФункцииКлиентСервер). Её логику легко повторить для букв любым из способов выше и положить функцию в свой общий модуль с флагами «Клиент» и «Сервер».

Какой способ проверки вам подходит?

Какой способ быстрее: сравнение методов и замер

Для одного поля на форме разницы нет: строка «Иванов Пётр Сергеевич» проверяется любым способом мгновенно. Скорость важна при массовой проверке — загрузке файла на 50 000 строк, обработке справочника, обмене.

СпособГде работаетСкорость на длинных строкахРиски
Цикл Сред + СтрНайтивездесредняя, растёт с длиной строкизабыть «ё» в алфавите
Цикл КодСимволавездесредняяошибиться в диапазонах
ВРег / НРегвездесредняябуквы без регистра
Каскад СтрЗаменитьвездевысокая на длинных строкахнеочевидный код
СтрСоответствуетШаблону8.3.23+высокаярежим совместимости
VBScript.RegExpтолько Windowsвысокая после создания объектане работает на Linux
ПОДОБНО в запросеСУБДлучшая для массовой проверкиправила сравнения СУБД

Каскад СтрЗаменить: быстрый вариант без регулярных выражений

Цикл по символам строки выполняется интерпретатором — каждая итерация стоит дорого. Можно перевернуть задачу: удалить из строки все допустимые буквы и посмотреть, осталось ли что-то. СтрЗаменить() работает внутри платформы, а итераций всегда 66 — по числу букв алфавита, а не символов строки.

Функция ТолькоБуквыЗаменой(Знач Строка) Экспорт

    Если ПустаяСтрока(Строка) Тогда
        Возврат Ложь;
    КонецЕсли;

    Алфавит = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя"
        + "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";

    Остаток = Строка;
    Для Позиция = 1 По СтрДлина(Алфавит) Цикл
        Остаток = СтрЗаменить(Остаток, Сред(Алфавит, Позиция, 1), "");
        Если Остаток = "" Тогда
            Прервать;
        КонецЕсли;
    КонецЦикла;

    Возврат Остаток = "";

КонецФункции

На коротких строках (до 20–30 символов) выигрыша нет, на абзацах текста он заметен.

Как замерить скорость самому

Цифры зависят от платформы и железа, поэтому сравнивайте на своих данных:

ТестоваяСтрока = "Константинопольский";
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
Для Номер = 1 По 100000 Цикл
    Результат = ТолькоРусскиеБуквы(ТестоваяСтрока);
КонецЦикла;
Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - Начало;
Сообщить("Мс: " + Формат(Длительность, "ЧГ=0"));

Замените вызов на другую функцию и сравните время. Запускайте замер на сервере: на клиенте при работе через интернет результат искажает сеть.

Краевые случаи: на чём ломается проверка строки на буквы

Функция, которая прошла тест на «Иванов» и «Иванов1», ещё не готова. Вот что реально приходит из форм, файлов и обменов:

  • ✏️ Пустая строка и пробелы. Цикл по пустой строке вернёт Истина. Отсекайте ПустаяСтрока() в начале.
  • ✏️ Пробелы по краям. «Иванов » с пробелом в конце — частый результат копирования. Перед проверкой делайте СокрЛП(Строка), если по смыслу пробелы не нужны.
  • ✏️ Неразрывный пробел (код 160). Приходит из Word, Excel и с веб-страниц. Выглядит как обычный, но проверка на пробел (код 32) его не узнает. Заменяйте: СтрЗаменить(Строка, Символ(160), " ").
  • ✏️ Дефис и апостроф. «Салтыков-Щедрин», «Д’Артаньян». Если проверяете ФИО, решите заранее, какие знаки допустимы, и не ставьте дефис первым или последним символом.
  • ✏️ Латиница внутри кириллицы. «Ивaнов» с латинской «a» (код 97) на экране неотличим от правильного. Проверка «любые буквы» его пропустит, проверка «только кириллица» — поймает. Для ФИО и наименований используйте именно кириллический алфавит.
  • ✏️ Составная «й». Текст из PDF и с macOS иногда хранит «й» как «и» плюс отдельный диакритический знак (код 774). Строка выглядит нормально, но проверка падает. Если такие данные встречаются, предварительно заменяйте пару символов на одну букву: СтрЗаменить(Строка, "и" + Символ(774), "й") и то же для заглавной.
  • ✏️ Значение не строкового типа. В функцию может прийти число или Неопределено. Добавьте в начало Если ТипЗнч(Строка) <> Тип("Строка") Тогда Возврат Ложь; КонецЕсли;.

Регистр в цикле с СтрНайти важен: «А» и «а» — разные символы. Если в алфавите только строчные буквы, приводите строку через НРег() перед проверкой.

Проверка на буквы при записи элемента и в запросе

Функция сама по себе ничего не защищает — её нужно вызвать в нужном месте.

Проверка заполнения в модуле объекта

Для реквизита справочника или документа проверку ставят в обработчик ОбработкаПроверкиЗаполнения модуля объекта. Он выполняется на сервере при записи из формы, а сообщение привязывается к полю:

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)

    Если ЗначениеЗаполнено(Фамилия) И Не ТолькоРусскиеБуквы(Фамилия) Тогда
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "Фамилия может содержать только русские буквы";
        Сообщение.Поле = "Фамилия";
        Сообщение.УстановитьДанные(ЭтотОбъект);
        Сообщение.Сообщить();
        Отказ = Истина;
    КонецЕсли;

КонецПроцедуры

Функцию ТолькоРусскиеБуквы разместите в общем модуле, доступном на сервере. В типовых конфигурациях такие доработки делают в расширении, чтобы не снимать конфигурацию с поддержки.

Для подсказки «на лету» продублируйте вызов в обработчике ПриИзменении поля формы. Но основная проверка — в модуле объекта: туда попадают и записи из обработок, и загрузка из файлов.

Поиск записей с недопустимыми символами в запросе

Чтобы найти уже испорченные данные, не перебирайте справочник циклом. Оператор ПОДОБНО в языке запросов понимает классы символов [...] и отрицание [^...]:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    ФизическиеЛица.Ссылка,
|    ФизическиеЛица.Наименование
|ИЗ
|    Справочник.ФизическиеЛица КАК ФизическиеЛица
|ГДЕ
|    ФизическиеЛица.Наименование ПОДОБНО ""%[^а-яА-ЯёЁ -]%""";
Выборка = Запрос.Выполнить().Выбрать();

Запрос вернёт элементы, в наименовании которых есть хотя бы один символ кроме русских букв, пробела и дефиса. Дефис стоит последним в классе, чтобы его не приняли за диапазон.

Диапазоны вроде а-я СУБД интерпретирует по своим правилам сравнения, они различаются в файловой базе, MS SQL и PostgreSQL. Проверьте результат на тестовой выборке с «ё», латиницей и цифрами, прежде чем строить на запросе массовое исправление.

Частые вопросы

Как проверить, что в строке только цифры?
В БСП есть готовая функция СтроковыеФункцииКлиентСервер.СтрокаСостоитИзЦифр(). Без БСП — тот же цикл, что и для букв, с алфавитом «0123456789», или шаблон ^[0-9]+$ в СтрСоответствуетШаблону.
Как проверить, что в строке есть хотя бы одна буква?
Логика обратная: в цикле возвращайте Истина на первой найденной букве и Ложь после цикла. Шаблоном — СтрНайтиПоРегулярномуВыражению с классом [а-яА-ЯёЁ] без якорей ^ и $.
Работают ли регулярные выражения 1С в веб-клиенте?
Функции встроенного языка из 8.3.23 доступны и на клиенте, и на сервере. COM-объект VBScript.RegExp в веб-клиенте недоступен вовсе — вызывайте его только в серверной процедуре на Windows.
Почему проверка не пропускает слово, которое выглядит правильно?
Почти всегда в строке есть невидимый или похожий символ: неразрывный пробел, латинская буква вместо русской, составная «й». Выведите коды символов через КодСимвола в цикле — лишний символ сразу будет виден.
Можно ли ограничить ввод букв прямо в поле формы?
Маска поля ввода подходит для фиксированных форматов вроде ИНН или телефона, для имён произвольной длины она неудобна. Надёжнее проверять в ПриИзменении поля и в ОбработкаПроверкиЗаполнения объекта.