При формировании печатных форм документов для иностранных контрагентов (например, инвойсов) разработчики часто сталкиваются с жесткими требованиями к оформлению финансовых показателей. В английском языке правила написания числительных строго регламентированы. Согласно правилам грамматики (как в американском en_US, так и в британском en_GB вариантах английского языка), составные числительные от 21 до 99 должны писаться через дефис (например, twenty-four, thirty-six). Кроме того, перед десятками и единицами в каждом разряде, а также перед центами принято ставить союз and.
Стандартная функция платформы 1С ЧислоПрописью() при базовых настройках выдает упрощенный вариант без дефисов и союза and (например, "Twenty four thousand one hundred thirty six"). В этой статье мы подробно разберем, как решить эту проблему с помощью современных штатных механизмов платформы 1С и эффективной обработки строк.
По умолчанию функция ЧислоПрописью() ориентирована на упрощенный стиль вывода чисел в английской локализации. Платформа опускает союз and и выводит составные числительные через пробел. Попытки просто поменять код локализации или использовать параметры по умолчанию не приносят желаемого результата, так как правила форматирования требуют явного указания дополнительных параметров в строке форматирования.
Давайте рассмотрим, как решить задачу комплексно: сначала заставим платформу выводить союз and на его законных местах, а затем разберем способы расстановки дефисов — от классических методов замены строк до максимально производительного современного решения на регулярных выражениях.
---
Начнем с союза and. Мало кто знает, но в платформе 1С:Предприятие для англоязычных локализаций существует специальный параметр форматирования — ИИ (в англоязычной нотации — AU). Этот параметр управляет использованием классической (полной) или упрощенной прописи:
ИИ=НеИспользовать (или отсутствие параметра) — используется упрощенная пропись без союза and.ИИ=Использовать — активирует классическую английскую пропись. Платформа начнет автоматически подставлять союз and между сотнями (или тысячами/миллионами) и последующими десятками/единицами в каждом разряде, а также перед дробной частью (центами).Проанализируем пример использования этого параметра:
// Формируем классическую пропись с союзом "and"
ФорматнаяСтрока = "L=en_US; ДП=Истина; ИИ=Использовать";
ПараметрыВалюты = "dollar, dollars, cent, cents, 2";
Результат = ЧислоПрописью(1234.56, ФорматнаяСтрока, ПараметрыВалюты);
// Полученный результат:
// "One thousand two hundred and thirty four dollars and fifty six cents"
Как мы видим, союз and автоматически встал на свои места: перед десятками долларов (and thirty four) и перед центами (and fifty six). Однако составные числительные по-прежнему выводятся через пробел. Перейдем к решении задачи с дефисами.
---
Для корректного преобразования пробелов в дефисы в составных числах существует три основных подхода. Рассмотрим их от простых и компромиссных к самым современным и быстродействующим.
Если бюджет разработки ограничен и не хочется перегружать систему сложными алгоритмами, можно воспользоваться простым и элегантным решением с последовательной заменой подстрок с помощью функции СтрЗаменить(). Метод основан на том, что составные числительные всегда оканчиваются на характерный суффикс десятков -ty.
Рассмотрим код этого решения:
ПредставлениеСуммы = ЧислоПрописью(Сумма, "L=en_US; ДП=Истина; ИИ=Использовать", "dollar, dollars, cent, cents, 2");
// Выполняем цепочку замен для расстановки дефисов
ПредставлениеСуммы = СтрЗаменить(ПредставлениеСуммы, "ty ", "ty-");
// Возвращаем пробелы там, где дефис не нужен (перед миллионами, тысячами и валютой)
ПредставлениеСуммы = СтрЗаменить(ПредставлениеСуммы, "ty-million", "ty million");
ПредставлениеСуммы = СтрЗаменить(ПредставлениеСуммы, "ty-thousand", "ty thousand");
ПредставлениеСуммы = СтрЗаменить(ПредставлениеСуммы, "ty-dollar", "ty dollar");
Преимущества: Высокая скорость работы и простота реализации. Не требует современных версий платформы и работает на любых релизах 1С v8.
Недостатки: Этот метод является эвристическим. Если в названии вашей валюты или в других служебных словах встретится буквосочетание "ty " с пробелом, алгоритм выполнит некорректную замену. Также при переходе на другие валюты придется дополнять список исключений (например, добавлять исключения для евро, фунтов и т.д.).
---
Чтобы гарантировать стопроцентную точность без риска задеть лишние слова, можно использовать точечную замену числительных от 21 до 99. Для этого мы в цикле получаем прописной вариант каждого составного числа и заменяем его пробел на дефис в итоговой строке.
Проанализируем пример функции, реализующей этот алгоритм:
Процедура ПреобразоватьПредставлениеПоПравилу(ПредставлениеСуммы)
// Перебираем все возможные составные числительные от 21 до 99
Для Итератор = 21 По 99 Цикл
// Проверяем, делится ли число на 10 (числа типа 30, 40, 50 пишутся без дефиса)
Если Итератор % 10 = 0 Тогда
Продолжить;
КонецЕсли;
// Получаем написание текущего составного числительного на английском языке
ТекПредставление = ЧислоПрописью(Итератор, "L=en_US; НП=Ложь;", ",,,,0");
// Обрабатываем вариант с заглавной буквы (если число стоит в начале строки)
Если СтрНайти(ПредставлениеСуммы, ТекПредставление) > 0 Тогда
НовоеПредставление = СтрЗаменить(ТекПредставление, " ", "-");
ПредставлениеСуммы = СтрЗаменить(ПредставлениеСуммы, ТекПредставление, НовоеПредставление);
КонецЕсли;
// Обрабатываем вариант в нижнем регистре (для середины строки)
ТекПредставлениеНРег = НРег(ТекПредставление);
Если СтрНайти(ПредставлениеСуммы, ТекПредставлениеНРег) > 0 Тогда
НовоеПредставлениеНРег = СтрЗаменить(ТекПредставлениеНРег, " ", "-");
ПредставлениеСуммы = СтрЗаменить(ПредставлениеСуммы, ТекПредставлениеНРег, НовоеПредставлениеНРег);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Преимущества: Абсолютная грамматическая точность. Заменяются только реальные числа, никакие сторонние слова или названия валют не будут повреждены.
Недостатки: Низкая производительность. Выполнение около 80 итераций цикла с операциями поиска подстроки (СтрНайти) и замены (СтрЗаменить) на каждое формирование печатной формы может существенно замедлить групповую печать или проведение документов на сервере.
---
Начиная с версии платформы 1С:Предприятие 8.3.23, разработчикам доступен мощный встроенный инструмент — работа с регулярными выражениями по стандарту ICU на уровне платформы. Это позволяет выполнить точную замену пробелов на дефисы в составных числительных всего за один проход, без использования циклов и громоздких условий.
Для решения нашей задачи мы воспользуемся механизмом регулярного выражения с ретроспективной ((?<=...)) и опережающей ((?=...)) проверками. Мы будем искать только те пробелы, перед которыми стоит десяток (от twenty до ninety) и после которых идет единица (от one до nine).
Разберем готовый шаблон регулярного выражения:
(?<=\b(?:[Tt]wenty|[Tt]hirty|[Ff]orty|[Ff]ifty|[Ss]ixty|[Ss]eventy|[Ee]ighty|[Nn]inety))\s+(?=(?:[Oo]ne|[Tt]wo|[Tt]hree|[Ff]our|[Ff]ive|[Ss]ix|[Ss]even|[Ee]ight|[Nn]ine)\b)
Этот шаблон работает следующим образом:
(?<=\b(?:...)) проверяет, что перед пробелом находится граница слова и одно из названий десятков (с учетом регистра).\s+ находит один или несколько пробельных символов между десятком и единицей.(?=(?:...)\b) проверяет, что сразу после пробела идет одно из названий единиц и граница слова.Посмотрим, как выглядит применение этого метода во встроенном языке 1С:
// 1. Формируем исходную пропись с использованием союза "and"
ФорматнаяСтрока = "L=en_US; ДП=Истина; ИИ=Использовать";
ПараметрыВалюты = "dollar, dollars, cent, cents, 2";
Пропись = ЧислоПрописью(24136.69, ФорматнаяСтрока, ПараметрыВалюты);
// Базовый результат:
// "Twenty four thousand one hundred and thirty six dollars and sixty nine cents"
// 2. Определяем шаблон регулярного выражения для поиска нужных пробелов
ШаблонДефисов = "(?<=\b(?:[Tt]wenty|[Tt]hirty|[Ff]orty|[Ff]ifty|[Ss]ixty|[Ss]eventy|[Ee]ighty|[Nn]inety))\s+(?=(?:[Oo]ne|[Tt]wo|[Tt]hree|[Ff]our|[Ff]ive|[Ss]ix|[Ss]even|[Ee]ight|[Nn]ine)\b)";
// 3. Выполняем замену нативного движка регулярных выражений 1С
ИтоговыйТекст = СтрЗаменитьПоРегулярномуВыражению(Пропись, ШаблонДефисов, "-");
// Итоговый корректный результат:
// "Twenty-four thousand one hundred and thirty-six dollars and sixty-nine cents"
Преимущества:
\b и строгих списков десятков и единиц гарантирует, что пробелы в словосочетаниях вроде "twenty thousand" или "thirty dollars" останутся нетронутыми.---
Для получения корректной английской прописи в соответствии со всеми правилами финансовой грамматики мы рекомендуем придерживаться следующих правил:
ИИ=Использовать (или AU), чтобы платформа автоматически расставляла союз and.СтрЗаменитьПоРегулярномуВыражению с предложенным паттерном. Это наиболее производительный и чистый с точки зрения кода подход.