Автоматическое разбиение строки на подстроки по ширине колонки / ячейки или по количеству символов

Опубликовал Сергей Мартин (SvoyakMartin) в раздел Обработки - Универсальные обработки

Длинный адрес контрагента или нестандартная фамилия не входит в одну строку, а РазмещениеТекста = Переносить по какой-либо причине не устраивает? Что можно сделать? Вот пара полезных функций для решения данного вопроса с примерами применения.

При работе с печатными формами периодически возникает одна и та же ситуация, когда строка, передаваемая параметром, не вмещается в выделенную для неё область.

Первое, что приходит на ум - просто изменить режим размещания текста:

ТекОбласть.РазмещениеТекста = ТипРазмещенияТекстаТабличногоДокумента.Переносить;

переносить

Но такой вариант не всегда подходит. Например, требуется, чтобы чтобы у области было нижнее подчёркивание вне зависимости от заполнения. Тогда можно использовать нижнюю границу ячейки, но если строк борее одной(в результате переноса), тогда подчёркнутой окажется лишь нижняя. Можно поизвращаться с самой входной строкой, вставляя лишние пробелы или знак "_" и используя подчёркнутый шрифт, но проще и правильнее, как мне кажется, вывести область несколько раз передавая в неё параметром нужную часть строки. И здесь возникает необходимость разбить строку на подстроки.

Вариант 1. По количеству символов строки.

Функция СтрРазбитьНаПодстроки(ИсходнаяСтрока, КоличествоСимволовПодстроки)
	КоличествоСимволовПодстроки = ?(КоличествоСимволовПодстроки < 1, 1, КоличествоСимволовПодстроки);
	ИсходнаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символы.ПС, " ");
	//разбить строку на максимальную длину в строке с учётом пробелов
	Пока Истина Цикл
		//получить кол-во строк
		КолВоСтрок = СтрЧислоСтрок(ИсходнаяСтрока);
		//взять последнюю
		ТекСтрока = СтрПолучитьСтроку(ИсходнаяСтрока, КолВоСтрок);
		//если длинее максимума
		Если СтрДлина(ТекСтрока) > КоличествоСимволовПодстроки Тогда
			ТекущаяПозиция = КоличествоСимволовПодстроки;
			СтрВставитьКудаНадоПС(ИсходнаяСтрока, ТекСтрока, КоличествоСимволовПодстроки);
		Иначе
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ИсходнаяСтрока;
КонецФункции
Процедура СтрВставитьКудаНадоПС(ИсходнаяСтрока, ТекСтрока, КоличествоСимволовПодстроки)
	//найти в ней последний пробел
	ТекущаяПозиция = КоличествоСимволовПодстроки;
	ДлинаПодСтроки = СтрДлина(ТекСтрока);
	Пока Истина Цикл
		Если КодСимвола(ТекСтрока, ТекущаяПозиция) = 32 Тогда
			//заменить пробел на перенос
			ВремСтрока = Лев(ТекСтрока, ТекущаяПозиция - 1) + Символы.ПС + Сред(ТекСтрока, ТекущаяПозиция + 1, ДлинаПодСтроки - ТекущаяПозиция);
			//заменить строку в основной
			ИсходнаяСтрока = СтрЗаменить(ИсходнаяСтрока, ТекСтрока, ВремСтрока);
			Прервать;
		ИначеЕсли ТекущаяПозиция = 1 Тогда
			//отрезать первый кусок
			ПоБуквам = (КоличествоСимволовПодстроки = 1);
			ВремСтрока = Лев(ТекСтрока, ?(ПоБуквам, КоличествоСимволовПодстроки, КоличествоСимволовПодстроки - 1)) + ?(ПоБуквам, "", "-") + Символы.ПС + Сред(ТекСтрока, ?(ПоБуквам, КоличествоСимволовПодстроки + 1, КоличествоСимволовПодстроки), ДлинаПодСтроки - (КоличествоСимволовПодстроки - 1));
			//заменить строку в основной
			ИсходнаяСтрока = СтрЗаменить(ИсходнаяСтрока, ТекСтрока, ВремСтрока);
			Прервать;
		КонецЕсли;
		ТекущаяПозиция = ТекущаяПозиция - 1;
	КонецЦикла;
КонецПроцедуры

Разбивка по пробелам есть, символ переноса, если слово не входит целиком есть, "защита от дурака" есть. Кстати, если передать вторым параметром 1, то получим преобразвание строки в "столбец".

Как узнать что передать в КоличествоСимволовПодстроки? Методом тыка или вводя в макете символы до заполнения области и, посчитав количество получившихся символов, использовать это значение.

Неплохо! С оговоркой, неплохо это только для моноширных шрифтов. А с обычными получается следующее. Посчитали, сколько входит единиц, а передав строку с буквами типа "Щ", "Ж", "Ю" окажется, что она не войдёт в область. Стоит это иметь ввиду и передавать количество символов с расчётом на самые широкие, но тогда в случае попадания узких символов, может показаться не очевидным, зачем произошёл перенос, если до правой границы ещё достаточно свободного места.

Вариант 2. По ширине ячейки / колонки.

Что изменяется из свойств области при переполнении? Высота! Отлично, она и будет индикатором для переноса строки.

Функция СтрРазбитьНаПодстрокиПоШиринеЯчейки(ТабДок, ТабДокОбластьЯчейки, ИсходнаяСтрока)
	ИсходнаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символы.ПС, " ");
	//разбить строку на максимальную длину в строке с учётом пробелов
	Пока Истина Цикл
		//получить кол-во строк
		КолВоСтрок = СтрЧислоСтрок(ИсходнаяСтрока);
		//взять последнюю
		ТекСтрока = СтрПолучитьСтроку(ИсходнаяСтрока, КолВоСтрок);
		//если длинее максимума
		ДлинаПодСтроки = СтрДлина(ТекСтрока);
		//получить максимум
		Позиция = 1;
		Пока Позиция < ДлинаПодСтроки Цикл
			Если ПроверитьОднострочныйВыводТекстаВЯчейку(ТабДок, ТабДокОбластьЯчейки, Лев(ТекСтрока, Позиция)) Тогда
				Позиция = Позиция + 1;
			Иначе
				Позиция = Позиция - 1;
				Прервать;
			КонецЕсли;
		КонецЦикла;
		Позиция = ?(Позиция < 1, 1, Позиция);
		КоличествоСимволовПодстроки = Позиция;
		Если ДлинаПодСтроки > КоличествоСимволовПодстроки Тогда
			ТекущаяПозиция = КоличествоСимволовПодстроки;
			СтрВставитьКудаНадоПС(ИсходнаяСтрока, ТекСтрока, КоличествоСимволовПодстроки);
		Иначе
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ИсходнаяСтрока;
КонецФункции
Процедура СтрВставитьКудаНадоПС(ИсходнаяСтрока, ТекСтрока, КоличествоСимволовПодстроки)
	//найти в ней последний пробел
	ТекущаяПозиция = КоличествоСимволовПодстроки;
	ДлинаПодСтроки = СтрДлина(ТекСтрока);
	Пока Истина Цикл
		Если КодСимвола(ТекСтрока, ТекущаяПозиция) = 32 Тогда
			//заменить пробел на перенос
			ВремСтрока = Лев(ТекСтрока, ТекущаяПозиция - 1) + Символы.ПС + Сред(ТекСтрока, ТекущаяПозиция + 1, ДлинаПодСтроки - ТекущаяПозиция);
			//заменить строку в основной
			ИсходнаяСтрока = СтрЗаменить(ИсходнаяСтрока, ТекСтрока, ВремСтрока);
			Прервать;
		ИначеЕсли ТекущаяПозиция = 1 Тогда
			//отрезать первый кусок
			ПоБуквам = (КоличествоСимволовПодстроки = 1);
			ВремСтрока = Лев(ТекСтрока, ?(ПоБуквам, КоличествоСимволовПодстроки, КоличествоСимволовПодстроки - 1)) + ?(ПоБуквам, "", "-") + Символы.ПС + Сред(ТекСтрока, ?(ПоБуквам, КоличествоСимволовПодстроки + 1, КоличествоСимволовПодстроки), ДлинаПодСтроки - (КоличествоСимволовПодстроки - 1));
			//заменить строку в основной
			ИсходнаяСтрока = СтрЗаменить(ИсходнаяСтрока, ТекСтрока, ВремСтрока);
			Прервать;
		КонецЕсли;
		ТекущаяПозиция = ТекущаяПозиция - 1;
	КонецЦикла;
КонецПроцедуры
Функция ПроверитьОднострочныйВыводТекстаВЯчейку(ТабДок, ТабДокОбласть, Текст)
	ИсходнаяВысота = ПолучитьВысотуОбласти(ТабДок, ТабДокОбласть);
	
	ВремТабДок = Новый ТабличныйДокумент;
	ВремТабДок.Вывести(ТабДок);
	ТекОбласть = ВремТабДок.Область(ТабДокОбласть.Имя);
	ТекОбласть.АвтоВысотаСтроки = Истина;
	ТекОбласть.РазмещениеТекста = ТипРазмещенияТекстаТабличногоДокумента.Переносить;
	
	ТекОбласть.ВысотаСтроки = 0;
	ТекОбласть.Текст = Текст;
	ТекВысота = ПолучитьВысотуОбласти(ВремТабДок, ТекОбласть);
	
	Возврат ?(ИсходнаяВысота = ТекВысота, Истина, Ложь);
КонецФункции
Функция ПолучитьВысотуОбласти(ТабДок, ТекОбласть)
	Заглушка = ТабДок.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Текст);
	Заглушка.Расположить(ТекОбласть);
	ВысотаЯчейки = Заглушка.Высота;
	ТабДок.Рисунки.Удалить(Заглушка);
	Возврат(ВысотаЯчейки);
КонецФункции

Ну и выводим в табличный документ преобразованную строку:

ИсходнаяСтрока = "Очень длинная строка, неспособная войти в выделенную для неё область";

ТабДок = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("Макет");
НекаяОбласть = Макет.ПолучитьОбласть("НекаяОбласть");
	
ФорматированнаяСтрока = СтрРазбитьНаПодстрокиПоШиринеЯчейки(НекаяОбласть, НекаяОбласть.Область("R1C2"), ИсходнаяСтрока);
	
Для ё = 1 По СтрЧислоСтрок(ФорматированнаяСтрока) Цикл
	НекаяОбласть.Параметры.НекийПараметр = СтрПолучитьСтроку(ФорматированнаяСтрока, ё);
	ТабДок.Вывести(НекаяОбласть);
КонецЦикла;

Вариант 3. Не разбивать строку, а уменьшать шрифт.

Лично меня такой вариант не устраивает минимум по трём причинам:

  1. Размер шрифта ниже некоего становится нечитаемым (порог достигается раньше, если зрение неидеальное).
  2. Печатному документу могут диктоваться стогие правила оформления/форматирования.
  3. Размер шрифта достиг минимально возможного, но текст так и не вместился.

Методика та же, что и в варианте 2, с той разницей, что играться прийдётся не с длиной строки, а с размером шрифта.

В приложенном файле обработка(та, что на скриншотах), демонстрирующая варианты применения данных функций.

Надеюсь кому-то окажется полезным. 

Скачать файлы

Наименование Файл Версия Размер
АвтоматическоеРазбиениеСтрокиНаПодстроки
.epf 9,87Kb
13.10.16
2
.epf 9,87Kb 2 Скачать

См. также

Комментарии
1. Александр Губанов (gubanoff) 43 21.10.16 16:03 Сейчас в теме
(0) порекламирую свою публикацию, которая также разбивает предложение на строки с заданным числом символов, но делает это по слогам Красивый перенос строк по слогам
2. Александр Гладких (yku) 261 28.10.16 12:19 Сейчас в теме
И у меня очень похожий приём используется. В комментариях много всякого предложили.
http://infostart.ru/public/123769/
Оставьте свое сообщение