Строка без цифр и знаков: проверяем буквы во встроенном языке 1С 8.3
Содержание
Чтобы проверить, что в строке только буквы, в 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–Z | 65–90 | латиница, заглавные |
| a–z | 97–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. Проверьте результат на тестовой выборке с «ё», латиницей и цифрами, прежде чем строить на запросе массовое исправление.