SysString – это классы на языке X++ для работы со строками и текстом (TextBuffer) в Microsoft Dynamics AX 2009, Microsoft Dynamics AX 2012 и Axapta 4.0.
Класс String
— отдельный класс, который содержит статические методы для работы со строками.
Класс SysText
расширяет (extends) класс TextBuffer
и содержит статические методы для работы с содержимым текстового буфера.
Аксапта позволяет использовать raw-литералы для строк. Однако внутри raw-литерала оступы никак не учитываются. А хотелось бы.
Особенно для SQL-команд, которые потом приходится видеть в SQL Management Studio
.
Детальное описание проблемы можно найти в JEP 355: Text Blocks, а краткую спецификацию в описании функции trimIdent для Kotlin.
Метод trimIdent
:
- удаляет первую и последнюю пробельные строки (пустая строка или строка, состоящая только из пробелов)
- вычисляет минимальный отступ у оставшихся строк, не учитывая пробельные строки внутри
- удаляет минимальный отступ у всех строк
- пробельные строки преобразует в пустые строки
Например:
str withoutIndent = String::trimIdent(@"
ABC
123
456
");
;
info(withoutIndent); // ABC\n123\n456
Примечание: Метод трактует символы табуляции как значимые символы, а не как пробелы
Еще пример:
// Create the SQL Server Instead Of Trigger
createTriggerSQL = String::trimIdent(@"
CREATE TRIGGER [dbo].[ShipCarrierStagingInsTrig] ON [dbo].[%1] INSTEAD OF INSERT AS
BEGIN
DECLARE @RecId AS bigint
SELECT @RecId = max(RecId) FROM %1 WITH (UPDLOCK, HOLDLOCK)
IF @RecId IS NULL BEGIN SELECT @RecId = 0 END
INSERT INTO %1
(%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,
%12,%13,%14,%15,%16,%17,%18,%19)
select
%2,%3,ISNULL(%4,''),getdate(),
case
when ISNULL(%6,0.0) != 0.0 then %6
else
cast(
case
when %20 is null then '0.0'
when %20 = '' then '0.0'
else %20
end
as numeric(28,12))
end,
....
END
");
Вспомогательная функция, которая используется в trimIdent
. Вычисляет отступ в многострочном тексте.
Примечание: Метод трактует символы табуляции как значимые символы, а не как пробелы
Вспомогательная функция, которая используется в trimIdent
.
Увеличивает или уменьшает отступ на указанное число пробелов у строк в textBuffer
. Не изменяет количество строк.
Примечание: Метод трактует символы табуляции как значимые символы, а не как пробелы
Ранее представленный проект SysGlobal также содержит
дополнительные функции для работы со строками. Однако некоторые разработчики посетовали, что внутренним регламентом
им запрещено модифицировать стандартные framework-классы вообще и класс Global
в частности.
Поэтому в данном проекте функции добавлены в класс String
, а не в Global
(хотя trimIdent
очень просится в Global
).
В дальнейшем я планирую перенести строковые функции в класс String
, а также добавить
другие вспомогательные функции типа drop
, hexDump
и т.п., которые полезны, но были явно лишними в Global
.
Но также буду рад услышать ваши предложения какие функции были бы полезными в классе String
.
Крепко думал перед публикацией проекта, решил остановиться на статических методах.
Буду рад услышать ваши замечания и доводы в пользу методов инстанса.
Крепко думал и решил оставить только встроенную в Аксапту функциональность для работы с регулярными выражениями (см. методы calcIdent
и changeIdent
). Буду рад услышать ваши замечания и доводы в пользу .net
-регулярных выражений.
Когда будете измерять производительность, примите во внимание, что Аксапта "работает" с
.net
версии 3.5, а не с современными версиями.net
. Да, современные библиотеки.net
во многом подменяют функции старых библиотек. Но вполне возможна ситуация, когда на компьютере с Аксаптой современные библиотеки просто не установлены.
Также рассматривал возможность вообще обойтись без регулярных выражений, но вариант с перебором получился слишком медленным.
Буду рад услышать ваши предложения как сделать код быстрее вообще без регулярных выражений.
Сейчас в методе SysText::trimIdent
происходит копирование текста из исходного TextBuffer
в промежуточный.
Поскольку аксаптовский TextBuffer
является аналогом дот-нетовского StringBuilder
, то в момент копирования происходит долгая сборка сегментов текста в TextBuffer
и выделение потенциально большого и непрерывного куска в памяти. Конечно, эта операция потенциально ускоряет textBuffer.subStr
, которые происходят позже. Но все равно хотелось бы избавиться от этого копирования, а просто передавать начало и конец сегмента в метод changeIdent
.
Буду рад услышать ваши предложения и замечания.
Буду признателен за ваши замечания, предложения и советы по проекту как в разделе Issues, так и в виде письма на адрес mazzy@mazzy.ru
Мазуркин Сергей (mazzy)