ShortString — Тип Delphi


Содержание

Почему Delphi предупреждает при назначении ShortString строке?

Я конвертирую какой-то старый код в Delphi 2010.

Существует множество старых ShortStrings, таких как строка [25]

Почему следующее назначение:

заставляет компилятор генерировать это предупреждение:

Здесь нет потери данных. В каких обстоятельствах это предупреждение будет полезной для меня информацией?

Тип ShortString не изменился. Он по-прежнему остается массивом AnsiChar.

Назначив его типу string, вы берете то, что является группой AnsiChars (один байт) и помещает его в группу WideChars (два байта). Компилятор может сделать это просто отлично и достаточно умен, чтобы не потерять данные, но предупреждение должно сообщить вам, что такое преобразование имело место.

Это потому, что ваш код неявно преобразовывает однобайтную строку символов в UnicodeString. Это предупреждает вас, если вы, возможно, не обратили на это внимания, поскольку это может вызвать проблемы, если вы сделаете это по ошибке.

Чтобы убрать его, используйте явное преобразование:

Предупреждение очень важно, поскольку вы можете потерять данные. Преобразование выполняется с использованием текущего 8-битного набора символов Windows, а некоторые наборы символов не определяют все значения от 0 до 255 или являются многобайтовыми наборами символов и, следовательно, не могут преобразовывать все байтовые значения.

Потеря данных может произойти на стандартном компьютере в стране со специальными стандартными наборами символов или на компьютере в США, который настроен для другого языкового стандарта, поскольку пользователь много общается с людьми на других языках.

Например, если локальная кодовая страница имеет значение 932, значения 129 и 130 байта оба преобразуются в одно и то же значение в строке Unicode.

В дополнение к этому, преобразование включает вызов Windows API, что является дорогостоящей операцией. Если вы сделаете много из них, это может замедлить ваше приложение.

Это безопасно (если вы используете ShortString по своему назначению: удерживать строку символов, а не набор байтов, некоторые из которых могут быть 0), но могут иметь последствия для производительности, если вы это сделаете много. Насколько мне известно, Delphi должен выделять память для новой строки юникода, извлекать символы из ShortString в строку с завершающим нулем (почему важно, чтобы она была правильно сформированной строкой), а затем вызвать что-то вроде Windows API Функция MultiByteToWideChar(). Не ракетостроение, но и не тривиальная операция.

У ShortStrings нет связанной с ними кодовой страницы, AnsiStrings (начиная с D2009).

Преобразование из ShortString в UnicodeString может быть выполнено только при условии, что ShortStrings кодируются в кодировке ANSI по умолчанию, которая не является безопасным допущением.

Я действительно не знаю Delphi, но если я правильно помню, Shortstrings — это, по сути, последовательность символов в стеке, тогда как регулярная строка (AnsiString) на самом деле является ссылкой на местоположение в куче. Это может иметь разные последствия.

Я думаю, что также может быть разница в терминах кодирования, но я не уверен на 100%.

Посмотрите другие вопросы по метке delphi или Задайте вопрос

ShortString — Тип Delphi

Пишу библиотеку.
В языке, на котором будет при программировании использоваться эта библиотека возможно передовать и принимать параметры только в shortString.
Как в delphi перевести string в shortString?

var S : String;
SS : ShortString;

не катит.
у меня вызывается в библиотеке функция, котора возвращает результат в string. Если это значение присваивать параметру моей функции типа ShortString, то возникает исключение.


> Покажи

Чего показать?
код?
Function READHEADERMAIL(var subjectmail: shortString): shortString; register;
.
msg:=tIDMessage.Create(nil);
.
Try
subjectmail:=Msg.Subject;
Except
Result:=»Error»#13″Не могу прочитать тему письма!»;
end;
.

возвращает в результат сообщение об ошибке.

В каком месте и какая ошибка ?

Угу, пишу dll.
Именно при выполнении subjectmail:=Msg.Subject; возникает ошибка, в результате чего функция возвращает значение «Error»#13″Не могу прочитать тему письма!»;

при компиляции ошибок нет

Читал что написано в коменте при создании пустого проекта DLL (ShareMem) ?

А какая всетаки ошибка ?

С этой ошибко йразобрался, теперь другая, подобная :))

Function READHEADERMAIL(var d1: shortString): shortString; register;
var ss: string;
.
msg:=tIDMessage.Create(nil);
.
Try
ss:=DateToStr(Msg.Date);
d1:=ss;
Except
on E: Exception do
begin MessageDlg(E.Message, mtInformation, [mbOk], 0);
Result:=»Error»; end;
end;
.

присвоение значения переменной ss происходит нормально, при присвоении значения переменной d1 выдает ошибку
Access violation at adress . in module «. dll». Write of adress .

И еще, по поводу первой ошибки:
результат возвращается в сабжект не весь, а только первое слово из строки, с чем может быть связано?
Пример сабжект имеет значение Test sub
в переменную subjectmail возвращается только Test

А у меня не выдает.
Уверен что при присвоении d1:=ss, а не при ss:=DateToStr(Msg.Date); ?

Как вызываем ?
FreeLibrary делаем ?

уверен, так как при коментировании d1:=ss; функция вызывается нормально.
Самое интересное, что при компиляции в делфях ошибки нет, но при вызове функции из библиотеки моей программы выдается такая ошибка.

зачем FreeLibrary ?
как вызывается из моего приложения?


> it_work © (02.05.06 09:22) [14]

Попробуй в DLL вместо ss:= DateToStr(msg.Date); поставить ss:= DateToStr(Now) у меня работает.
А отладчиком не пробовал пользоваться Run -> Attach to process

Отладчик есть для этого — прекрасно трассирует библиотеки
только не Run -> Attach to process
а
Run -> paremeters -> host application


> Попробуй в DLL вместо ss:= DateToStr(msg.Date); поставить
> ss:= DateToStr(Now) у меня работает.

Та же самая ерунда, ошибка вываливается именно при присвоении значения из ss в d1
А ты пробуешь просто в приложении или в dll?
В приложении и у меня работает :))


> it_work © (02.05.06 09:47) [17]
> А ты пробуешь просто в приложении или в dll?

function DD(var SS: ShortString): ShortString; register;
var
S: String;
begin
S:= DateToStr(Now);
SS:= s;
Result:= ss;
end;


> Отладчик есть для этого — прекрасно трассирует библиотеки
> только не Run -> Attach to process
> а
> Run -> paremeters -> host application

не все так просто, в приложении в котором используется эта библиотека своих библиотек штук 40 и все функции переплетены как черти, просто так не отладишь :( поэтому мессаги и поставил


> В DLL
>
> function DD(var SS: ShortString): ShortString; register;
>
> var
> S: String;
> begin
> S:= DateToStr(Now);
> SS:= s;
> Result:= ss;
> end;

проверяешь значение самой функции или ss при вызове функции?

Бред какой-то, когда пихаю значение в result все нормально

procedure TForm1.Button1Click(Sender: TObject);
type
TFun = function(var dd: ShortString): ShortString;
var
h: Cardinal;
p: Pointer;
t: TFun;
d: shortstring;
begin
h:= LoadLibrary(«DLL.DLL»);
p:= GetProcAddress(h,»DD»);
if p<>nil then begin
T:= P;
d:= «ggg»;
showmessage(T(d));
showmessage(d);
FreeLibrary(h);
end;
end;


Соглашения о вызовах в DLL и в приложении не попутаны, часом?

нет, так как остальные функции работают нормально и прямое присвоение значения типа d:=»11″ отрабатывает нормально


> it_work © (02.05.06 12:57) [24]

При чем тут остальные ?

Всё-таки, по тексту проверь, а не по косвенным соображениям.


> прямое присвоение значения типа d:=»11″ отрабатывает нормально

А прямое присваивание
d:=»qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq»
?

Т.к. у тебя var-параметр, проверь, имеет ли актуальный параметр достаточную длину, и не компилируется ли всё в режиме

Выставь глобально <$V+>(Project options|Compiler|Strict var-strings) и сделай build all.


> DiamondShark © (02.05.06 13:03) [27]

У него d1:= DateToStr(Msg.Date) а там от силы 10 символов.


> > прямое присвоение значения типа d:=»11″ отрабатывает
> нормально
>
> А прямое присваивание
> d:=»qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
> qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq»
> ?

у меня по тексту отправитель не длинная строка.
и ко всему моя функция возвращает результат типа ShortString, и что самое интересное присвоение result:=ss, где ss-string проходит нормально и без ошибок и возвращает правильно отправителя


> balepa © (02.05.06 13:07) [29]

А я откуда знаю, что ему реально в параметре приходит?
Он же отладчиком пользоваться отказывается, тесты не хочет выполнять, текст проверять тоже не хочет.
А телепатор, всё-таки, не казённый, батарейки к нему дорогие.


> it_work © (02.05.06 13:08) [30]

А ты попробуй, всё-таки.
Или возьми, наконец, отладчик, перед вызовом функции присвой параметру какую-нибудь характерную строку, «12345678фывапр», например, поставь в начале функции брекпоинт, и посмотри, что тебе там по ссылке передалось.

Ты понимаешь, что по симптомам — у тебя по ссылке приходит какая-то фигня. От предложенных вариантов ты отбрыкиваешься.
Как тебе ещё помочь?


> Ты понимаешь, что по симптомам — у тебя по ссылке приходит
> какая-то фигня. От предложенных вариантов ты отбрыкиваешься.
>
> Как тебе ещё помочь?

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

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

а с кодировками почты кто-нить может помочь?

AnsiString в Delphi

Строки в Delphi представляют собой последовательность символов. Можно разделить на 4 типа строки в Делфи:

  1. ShortString (максимальная длина – 255) используется для обратной совместимости. Нулевой символ отсутствует в конце.
  2. AnsiString (максимальная длина ˜2 Гб) используется для символов ANSI. Нулевой символ присутствует в конце.
  3. String (255 символов или до ˜2 Гб) используется для ANSI или Unicode. Нулевой символ может присутствовать или не присутствовать в конце.
  4. W >

Подробнее хочу остановиться на строковых типах ShortString и AnsiString. Они различаются между собой организацией хранения в памяти. Строки типа ShortString хранят в своем нулевом байте число символов в строке, а в последующих байтах – сами символы (не более 255). Поэтому, если Q – строка типа ShortString, то Ord(Q[0]) – то же, что и Length(Q), возвращает длину строки. Присваивание значения Q[0] соответствует вызову функции SetLength, которая устанавливает длину строки.

Переменная типа AnsiString является указателем на динамически выделяемую область памяти, в которой хранится строка. Может существовать несколько переменных, которые ссылаются на одну и ту же строку. В этом случае в памяти хранится только один экземпляр строки. Это экономит ресурсы. В случае, если строка равна 0, то этот указатель равен nil и память под строку не выделяется. Если же строка не пустая, то в выделенной памяти хранится сама строка, ее длина и число ссылок (переменных) ссылающихся на данную строку. Если переменной типа AnsiString присваивается новое значение, то число ссылок в прежней строке уменьшается на единицу, а в новой – увеличивается на единицу. Когда число ссылок на строку становится равным 0, то строка уничтожается, освобождая место в памяти.

Длинные строки типа AnsiString

Переменные этого типа объявляются обычным образом:

Var Q1: AnsiString;

Q2: string;

Объявление глобальных переменных или типизированных констант можно сочетать с инициализацией, причем нулевой символ в конце строки добавляется автоматически.

Var Q1: AnsiString = ‘текст’;

Q2: string = ‘начальный тест’;

Доступ к отдельным символам строки осуществляется как к символьному массиву по индексу (индекс отсчитывается от 1, а во всех других типах длинных строк индексы отсчитываются от 0). Для строки Q1 выражение Q1[2] возвращает символ строки ‘е’ – второй символ строки. Если индекс выходит за рамки числа символов в строке, то возвращается нулевой символ ‘#0’.

Функция Length(Q1) возвращает число символов строки, не считая нулевого символа. В данном случае Length(Q1) вернет 5.

Procedure SetLength(var Q; NewLength: Integer);

задает новый размер NewLength строки Q. Если NewLength меньше числа символов в строке, то текст строки усекается до указанного числа символов, иначе (т. е. больше), то прежний текст сохраняется, а после него записываются нулевые символы.

Для обработки строк типа AnsiString существует ряд библиотечных функций.

. delphi максимальный размер строки максимальная длина строки в delphi равна размер ansistring delphi ansistring макс длина delphi ansistring

Типы данных Delphi

Теперь обсудим типы данных Delphi, которые программист использует при написании программы. Любая программа на Delphi может содержать данные многих типов:

  • целые и дробные числа,
  • символы,
  • строки символов,
  • логические величины.

Целый тип Delphi

Библиотека языка Delphi включает в себя 7 целых типов данных: Shortint, Smallint, Longint, Int64, Byte, Word, Longword, характеристики которых приведены в таблице ниже.

Вещественный тип Delphi

Кроме того, в поддержку языка Delphi входят 6 различных вещественных типов (Real68, Single, Double, Extended, Comp, Currency), которые отличаются друг от друга, прежде всего, по диапазону допустимых значений, по количеству значащих цифр, по количеству байт, которые необходимы для хранения некоторых данных в памяти ПК (характеристики вещественных типов приведены ниже). Также в состав библиотеки языка Delphi входит и наиболее универсальный вещественный тип — тип Real, эквивалентный Double.

Символьный тип Delphi


Кроме числовых типов, язык Delphi располагает двумя символьными типами:

Тип Ansichar — символы c кодировкой ANSI, им ставятся в соответствие числа от 0 до 255;

Тип Widechar — символы с кодировкой Unicode, им ставятся в соответствие числа от 0 до 65 535.

Строковый тип Delphi

Строковый тип в Delphi обозначается идентификатором string. В языке Delphi представлены три строковых типа:

Тип Shortstring — присущ статически размещаемым в памяти ПК строкам, длина которых изменяется в диапазоне от 0 до 255 символов;

Тип Longstring — этим типом обладают динамически размещаемые в памяти ПК строки с длиной, ограниченной лишь объемом свободной памяти;

Тип WideString — тип данных, использующийся для того, чтобы держать необходимую последовательность Интернациональный символов, подобно целым предложениям. Всякий символ строки, имеющей тип WideString, представляет собой Unicode-символ. В отличие от типа Shortstring, тип WideString является указателем, который ссылается на переменные.

Логический тип Delphi

Логический тип соответствует переменным, которые могут принять лишь одно из двух значений: true, false. В языке Delphi логические величины обладают типом Boolean. Вам были представлены основные типы данных Delphi. Движемся дальше.

Почему Delphi предупредит при назначении ShortString в строку?

Я преобразования некоторого унаследованного кода в Delphi 2010.

Есть довольно много старых ShortStrings, как струны [25]

Почему ниже назначение:

заставляет компилятор генерировать это предупреждение:

Там нет потери данных, что происходит здесь. В каких обстоятельствах это предупреждение будет полезной информации для меня?

Это потому , что ваш код неявно преобразования строки символов однобайтных к UnicodeString. Это предупреждает вас в случае , если вы могли упустить из виду это, так как это может вызвать проблемы , если вы делаете это по ошибке.

Для того, чтобы сделать его уйти, использовать явное преобразование:

Тип ShortString не изменился. Он продолжает быть, в сущности, массив AnsiChar.

Назначая его строкового типа, вы принимаете, что группа содержащих AnsiChar’ы (один байт) и положить его в группу WideChars (два байта). Компилятор может сделать это просто отлично, и достаточно умен, чтобы не потерять данные, но предупреждение там, чтобы вы знали, что такое превращение произошло.

Предупреждение очень важно, потому что вы можете потерять данные. Преобразование выполняется с использованием текущей ОС Windows 8-битный набор символов, и некоторые наборы символов не определяют все значения от 0 до 255, или многобайтовые наборы символов, и, таким образом, не может преобразовать все значения байтов.

Может произойти потеря данных на стандартном компьютере в стране с определенными стандартными наборами символов, или на компьютере в США, которая была создана для другого языка, поскольку пользователь общается много с людьми на других языках.

Например, если локальная кодовая страница 932, байт значения 129 и 130 оба преобразовать в то же самое значение в строке Unicode.

В дополнение к этому, преобразование включает в себя API вызова Windows, которая является дорогостоящей операцией. Если вы делаете много из них, это может замедлить ваше приложение.

ShortStrings не имеют кодовую страницу, связанную с ними, AnsiStrings делать (с D2009).

Переход от ShortString к UnicodeString может быть сделано только при условии, что ShortStrings кодируются в кодировке ANSI по умолчанию, который не является безопасным предположением.

Это безопасно (до тех пор, как вы используете ShortString по своему прямому назначению: для хранения строки символов, а не сбор байтов, некоторые из которых могут быть 0), но может повлиять на производительность, если вы делаете это много. Насколько я знаю, Delphi должен выделить память для новой строки Юникода, извлекать символы из ShortString в строку с завершающим нулем (поэтому очень важно, что это правильно сформированная строка), а затем вызвать что-то вроде Windows API MultiByteToWideChar () функция. Не ракетостроение, но не тривиальная операция либо.

Я действительно не знаю Delphi, но если я правильно помню, то Shortstrings существу последовательность символов в стеке, в то время как регулярная строка (AnsiString) на самом деле ссылка на место в куче. Это может иметь различные последствия.

Я думаю, что также может быть разница с точки зрения кодирования, но я не уверен на 100%.

Why does Delphi warn when assigning ShortString to string?

I’m converting some legacy code to Delphi 2010.

There are a fair number of old ShortStrings, like string[25]

Why does the assignment below:

cause the compiler to generate this warning:

There’s no data loss that is occurring here. In what circumstances would this warning be helpful information to me?

6 Answers 6

The ShortString type has not changed. It continues to be, in effect, an array of AnsiChar.

By assigning it to a string type, you are taking what is a group of AnsiChars (one byte) and putting it into a group of WideChars (two bytes). The compiler can do that just fine, and is smart enough not to lose data, but the warning is there to let you know that such a conversion has taken place.

It’s because your code is implicitly converting a single-byte character string to a UnicodeString. It’s warning you in case you might have overlooked it, since that can cause problems if you do it by mistake.

To make it go away, use an explicit conversion:

The warning is very important because you may lose data. The conversion is done using the current Windows 8-bit character set, and some character sets do not define all values between 0 and 255, or are multi-byte character sets, and thus cannot convert all byte values.

The data loss can occur on a standard computer in a country with specific standard character sets, or on a computer in USA that has been set up for a different locale, because the user communicates a lot with people in other languages.

For instance, if the local code page is 932, the byte values 129 and 130 will both convert to the same value in the Unicode string.

In addition to this, the conversion involves a Windows API call, which is an expensive operation. If you do a lot of these, it can slow down your application.

DelphiComponent.ru — бесплатно видеоуроки по Delphi, статьи, исходники

Работа со строками в Delphi

Строковый тип данных — наиболее широко используемый тип данных в стандартных приложениях. При работе со строковыми значениями можно применять один из доступных строковых типов или массив символов. Delphi позволяет использовать операцию присваивания для присвоения строкового значения массиву символов.


Поскольку память для массива символов резервируется статически, размер массива не может изменяться во время выполнения и для него всегда резервируется стек размером 256 байтов, независимо от действительного количества символов в массиве.

Delphi по-прежнему поддерживает старый строковый тип языка Pascal, но в Delphi этот строковый тип называется ShortString. Память для типа ShortString, как и память для массива символов, резервируется статически, и этот тип всегда использует 256 байтов стековой памяти. Тип ShortString может содержать не более 255 символов. Первый символ, индекс которого равен 0. содержит длину строки — действительное количество символов в типе ShortString.

В следующем примере отображается длина и объем памяти, занимаемой переменной типа ShortString. Для выяснения количества байтов, занимаемых переменной, можно использовать функцию SizeOf.

Листинг 6.11. Сведения о переменной типа ShortString

Работа со строками в Delphi 10.3 Rio

Работа со строками в Delphi — это отдельная и очень обширная тема. Рассмотреть в одной статье все тонкости и особенности строк delphi представляет собой достаточно сложную задачу сравнимую, наверное, с написанием небольшой книги, просто по причине того, что в Delphi на сегодняшний день используются разные типы строк (ShortString, AnsiString, UnicodeString и прочие) и каждый тип для чего-то да нужен — для обратной совместимости, для COM BSTR, для разработки под мобильные платформы и так далее.

Вместе с этим, Delphi постоянно развивается, что-то добавляется, что-то улучшается и вот уже те инструменты работы со строками в Delphi, которые вызывали недоумение своим появлением, например, в Delphi 2009 в Delphi 10.3 Rio начинают играть другими красками. На написание этой статьи меня подтолкнула статья « What’s New » для Delphi 10.3 Rio, а именно то, что разработчики Delphi отдельным пунктом выделили, что давным давно существующий в Delphi класс TStringBuilder оптимизирован и даже обзавелся перегруженным методом ToString использование которого может увеличить производительность. Вот я и решил проверить — на сколько же выросла производительность TStringBuilder в Delphi по сравнению с тем, что было в далеком 2008 году, когда не было ни поддержки мобильных платформ, ни x64 с Linux.

Справка по TStringBuilder

TStringBuilder — это специализированный класс для работы со строками в Delphi (аналог класса StringBuilder в .NET Framework).

TStringBuilder поддерживает выполнение таких операций со строками как конкатенация (сложение), поиск, заменена и вставка подстрок. При этом, массив символов может быть запрошен по индексу или преобразован в строку для сравнения.

На массив символов можно ссылаться напрямую, используя свойство Chars. Свойство Length содержит текущую длину массива символов.

Работать с классом TStringBuilder в Delphi достаточно просто:

Обратить внимание стоит на то, что TStringBuilder работает с 0-индексированными (0-based) строками — первый символ имеет индекс 0, а не 1, как мы привыкли в Delphi. В остальном же, работа с TStringBuilder основана на использовании следующих методов:

Append — добавить подстроку к строке (конкатенация строк). Метод перегружен поэтому, Вы можете добавлять к строке числа, массивы символов и другие типы, например так:

Insert — вставить подстроку в строку с заданной позиции (метод также перегружен)

Replace — заменить подстроку (или символ) на другую строку (символ). Заменяет все вхождения подстрок.

CopyTo — копирование части строки в строку-приемник.

В Delphi 10.3 Rio TStringBuilder обзавелся также перегруженным методом ToString:

По сообщению разработчиков Delphi, ToString (True) даст лучшую производительность, если больше не ожидается никаких изменений для TStringBuilder, поскольку это уменьшает объем копируемых данных.

Со всеми методами TStringBuilder можно ознакомиться в справке Delphi.

Меня же больше интересует насколько TStringBuilder стал более производительным в части конкатенации строк по сравнению с обычной (привычной, классической) операцией сложения?

Вводные для теста производительности TStringBuilder

Итак, что у меня имеется для тестирования TStringBuilder:

Стационарный компьютер имеет следующие характеристики:

  • Процессор Intel Core i5 8400 (6-ти ядерный)
  • ОЗУ: 16 ГБ
  • ОС: Windows 10 x64

Смартфон LG Q7+ (Android 8.1.0)

Модель процессора MediaTek MT6750S
Частота процессора 1.5 ГГц
Кол-во ядер процессора 8
Оперативная память 3 ГБ

Проверять будем конкатенацию (сложение) строк Delphi в следующем порядке:

  1. Проверяем скорость сложения строк с использованием метода Append TStringBuilder
  2. Проверяем обычное сложение строк (Str1+Str2)
  3. Проверяем скорость сложения строк с использованием метода Append TStringBuilder и вывод строки обновленным методом ToString(True).

Все три проверки буду проводить на всех доступных устройствах.

Приложение для тестирование производительности TStringBuilder

Версия для ОС Windows

Внешний вид приложения для теста производительности TStringBuilder в Windows:

Каждую операцию сложения строк будем повторять по десять раз и результаты теста выводить в TStringGrid.

Код обработчика OnClick:

Результаты теста TStringBuilder в Windows

Тестирование сложение двух строк

  • Строка 1: edStr1
  • Строка 2: edStr2
  • Количество сложений: 30 000 000
# TStringBuilder Классика TStringBuilder.ToString(True)
1 234 483 165
2 249 527 163
3 197 482 155
4 206 495 157
5 186 503 155
6 185 503 162
7 188 499 155
8 188 519 155
9 187 478 155
10 208 537 154

Прибавление к строке одного символа

  • Строка 1: edStr1
  • Строка 2: a
  • Количество сложений: 30 000 000
# TStringBuilder Классика TStringBuilder.ToString(True)
1 149 314 124
2 149 318 128
3 137 332 207
4 122 312 123
5 121 311 123
6 146 312 173
7 130 327 124
8 122 315 124
9 122 317 123
10 122 312 123

Как можно видеть из представленных результатов TStringBuilder при сложении строк оказывается практически вдвое быстрее, чем обычная операция сложения, чего ранее за этим классом не наблюдалось при работе в Windows — ранее время, затрачиваемое на операцию сложения было практически одинаковым или, как в свое время проверял Marco Cantu — TStringBuilder оказывался намного медленнее.

Версия для ОС Android


Внешний вид приложения для тестирования TStringBuilder:

Исходный код программы тот же, что и в версии для Windows с одним лишь исключением — результаты теста будут выводиться в обычный Memo:

Результаты теста TStringBuilder на LG Q7+

Тестирование сложение двух строк

  • Строка 1: edStr1
  • Строка 2: edStr2
  • Количество сложений: 1 000 000
# TStringBuilder Классика TStringBuilder.ToString(True)
1 302 849 232
2 233 847 221
3 231 830 221
4 230 828 224
5 230 831 221
6 238 829 227
7 230 821 221
8 230 821 221
9 230 838 223
10 238 822 228

Прибавление к строке одного символа

  • Строка 1: edStr1
  • Строка 2: a
  • Количество сложений: 1 000 000
# TStringBuilder Классика TStringBuilder.ToString(True)
1 302 776 221
2 221 774 218
3 221 775 219
4 221 776 218
5 221 772 218
6 221 773 218
7 221 773 219
8 221 773 219
9 221 773 219
10 221 772 218

Опять же, как можно видеть по результатам тестирования, TStringBuilder ускоряет работу по сложению двух строк примерно в 2,5 раза, при этом, новый метод ToString(True) дает незначительное ускорение по сравнению с обычным ToString.

Резюмируем

На рисунке ниже представлено среднее время сложения двух строк в Windows.

  1. Синий столбик — сложение двух строк
  2. Оранжевый — прибавление к строке одного символа

То де самое, но уже для Android:

Представленные выше диаграммы наглядно демонстрируют рост производительности TStringBuilder при работе со строками в Delphi 10.3 Rio как в Windows, так и в Android. Между тем, новые метод TStringBuilder.ToStrng(True) дает незначительный прирост производительности по сравнению с ранее существующим методом ToString.

Таким образом, если в вашем приложении Delphi часто приходится иметь дело со строками, то, думаю, что имеет смысл обратит внимание на работу с TStringBuilder вне зависимости от того в какой операционной системе вы работаете.

Остается открытым вопрос о производительности TStringBuilder при работе в многопоточных приложениях, но это уже отдельная тема повышения производительности работы со строками в Delphi в принципе.

Исходники обоих тестовых приложений можно скачать со страницы:

Работа со строками в Delphi 10.1 Berlin

Автор: Alex. Опубликовано в Программирование 31 Январь 2020 . просмотров: 23144

Для работы со строками в последних версиях Delphi разработчикам доступно большое количество функций, помимо которых ещё есть помощники для работы со строками, такие как TStringHelper, TStringBuilder и TRegEx. Во всём этом разнообразии бывает сложно найти нужную функцию. Я попытался разобраться, что есть в Delphi 10.1 Berlin для работы со строками и как этим всем пользоваться.

Итак, прежде чем начнём разбираться с функциями, замечу, что начиная с Delphi XE3, появился помощник TStringHelper, и теперь работать со строками можно как с записями. Т.е., если вы определили переменную со строкой (на картинке снизу – это myStr), то вы можете поставить точку и посмотреть, какие функции доступны. Это очень удобно.

Кстати аналогичные помощники появились и для работы с типами Single, Double и Extended: TSingleHelper, TDoubleHelper и TExtendedHelper.

Ну и конечно, помимо помощника TStringHelper, никуда не делся класс TStringBuilder, который используется для работы со строкой как с массивом, и который является полностью совместимым с .NET классом StringBuilder.

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

Все приведённые в статье примеры сделаны с помощью Delphi 10.1 Berlin, поэтому в других версиях Delphi их работа не гарантируется.

Вот основные моменты, которые мы рассмотрим в статье:

Строки в Delphi

В последних версиях Delphi тип string, обозначающий строку, является псевдонимом встроенного типа System.UnicodeString. Т.е. когда вы объявляете переменную str: string, то автоматически вы объявляете переменную типа UnicodeString.

Кстати, на платформе Win32 вы можете использовать директиву « », которая превратит тип string в ShortString. С помощью этого способа вы можете использовать старый 16-битный код Delphi или Turbo Pascal в ваших проектах.

Обратите внимание, что кроме типа UnicodeString и ShortString в Delphi есть и другие типы строк, такие как AnsiString и WideString, однако дальше в статье мы будем рассматривать только работу со строками типа string.

Более глубокое изучение строк в Delphi вы можете начать с прочтения документации здесь.

Инициализация строк

Конечно, начнём мы с инициализации строк. Итак, рассмотрим объявление переменной с типом string.

В этой строчке кода мы объявляем переменную s с типом string, т.е., как было написано выше, по умолчанию с типом UnicodeString. Объявленные переменные с типом UnicodeString, в которые не присвоено значение, всегда гарантированно содержат строку нулевой длины. Чтобы теперь в переменной s была нужная нам строка, нужно просто присвоить переменной другое значение, например:

Это самый простой и часто используемый способ инициализации. Кроме этого есть ряд полезных функций, которые пригодятся вам для инициализации строк в некоторых ситуациях (здесь и далее я буду давать полный код проекта консольного Win32 приложения):

Изменение регистра

Для изменения регистра строк в Delphi есть функции LowerCase, UpperCase, TStringHelper.ToLower, TStringHelper.ToUpper, TStringHelper.ToLowerInvariant и TStringHelper.ToUpperInvariant. В нижний регистр строки меняют функции LowerCase, TStringHelper.ToLower и TStringHelper.ToLowerInvariant, остальные – в верхний. Обратите внимание, что функции LowerCase и UpperCase не работают с кириллицей. Функции TStringHelper.ToUpperInvariant и TStringHelper.ToLowerInvariant всегда работают независимо от текущей пользовательской локали. Вот примеры использования функций:

Конкатенация строк

Здесь конечно самый простой вариант – это использование оператора +. Но есть и другие варианты, например, функция Concat. А если вам нужно в цикле добавлять в конец одной строки большое количество других строк, то здесь пригодится метод Append класса TStringBuilder. Вот пример использования перечисленных способов:

Во всех четырёх переменных, после выполнения нашей программы, будет следующая строка: «Абвгдеёжзиклмнопрст». Четвёртый способ выглядит более громоздким, но у такого способа есть три преимущества. Во-первых, при большом количестве конкатенаций этот способ даст выигрыш по времени по сравнению с первыми тремя способами. Во-вторых, при создании объекта TStringBuilder вы сразу можете задать нужный размер массива для хранения строки, если он конечно известен. Это тоже даст выигрыш по времени. В-третьих, функция Append принимает на вход не только строки, но и другие типы, такие как Integer и Single, автоматически преобразуя их в строку.

Третий способ удобно использовать, если нужно сложить строки, находящиеся в массиве или списке. К тому же здесь первым параметром можно задать строку-разделитель, которая будет вставлена между строками, взятыми из массива. Вот пример, в котором формируется строка со списком городов, разделённых запятыми:

В результате выполнения этой функции получится строка «Москва, Санкт-Петербург, Севастополь».

Вставка подстроки в строку

Для того чтобы вставить внутрь строки подстроку вы можете использовать процедуру Insert или функцию TStringHelper.Insert. У класса TStringBuilder тоже есть аналогичная функция. Кстати, функция TStringBuilder.Insert, кроме строк умеет вставлять и другие типы, такие как Integer и Single, автоматически преобразуя их в строку. Вот пример использования:


Обратите внимание, в процедуре Insert нумерация символов начинается с 1, а в функциях TStringHelper.Insert и TStringBuilder.Insert – с 0. Все приведённые способы меняют строку, хранящуюся в переменной.

Удаление части строки

Допустим, вам нужно удалить из строки часть символов. Здесь нам помогут процедура Delete и функция TStringHelper.Remove. У класса TStringBuilder тоже есть функция Remove. Вот примеры использования:

Во всех трёх способах из строки «Абвгд» получится строка «Агд». Обратите внимание, что в процедуре Delete нумерация символов начинается с 1, а в функциях Remove – с 0.

Также интересно, что функция TStringHelper.Remove не трогает исходную строку. Вместо этого она возвращает новую строку с удалёнными символами. Именно поэтому мы присваиваем результат обратно в переменную. Процедура Delete работает по-другому: она меняет исходную строку.

Помимо приведённых здесь вариантов, для удаления части строки можно использовать функции замены подстроки, просто для этого искомая подстрока заменяется на пустую, например, StringReplace(str1, substr1, »).

Копирование части строки

Здесь идёт речь о том, что часть длиной строки нужно скопировать в новую строку или массив символов. Для этого в Delphi есть функции LeftStr, RightStr, Copy, TStringHelper.Substring и TStringHelper.CopyTo. А в классе TStringBuilder – только функция CopyTo. Есть также функция MidStr в юните System.StrUtils, которая работает аналогично функции Copy, поэтому в примере её не будет.

Первые два способа копируют часть строки слева (функция LeftStr) или справа (RightStr). Остальные четыре способа подходят, как для копирования части строки слева или справа, так и из середины.

В способах 3-6 из примера мы получим сроку «вгд» или массив [‘в’, ‘г’, ‘д’]. Обратите внимание, что в функциях Copy и MidStr нумерация символов начинается с 1, а во всех остальных с 0. Исходная строка или массив символов во всех четырёх способах не меняется.

Сравнение строк

Конечно, сравнивать строки можно с помощью операторов =, , >= и <>. Но кроме этого существуют ещё много функций: StrComp, StrIComp, StrLComp, StrLIComp, CompareStr, CompareText, TStringHelper.Compare, TStringHelper.CompareOrdinal, TStringHelper.CompareTo, TStringHelper.CompareText, SameStr, SameText, TStringHelper.Equals и TStringBuilder.Equals. Функции SameText, StrIComp, CompareText, TStringHelper.CompareText и TStringHelper.Compare умеют производить регистронезависимое сравнение строк, остальные функции и операторы — регистрозависимое.

Третьим параметром в функциях CompareText и SameText можно указать, что нужно использовать для сравнения строк пользовательскую локаль. В этом случае вы сможете сравнивать строки с русскими буквами независимо от регистра, если конечно в ОС используется русский язык.

Самая продвинутая здесь функция – это TStringHelper.Compare. С помощью неё можно сравнивать не только целые строки, но и части строк. Здесь можно настроить зависимость от регистра, включить игнорирование символов и знаков препинания или сравнение цифр как чисел и т.д.

Операторы, а также функции TStringHelper.Equals и TStringBuilder.Equals, в результате сравнения, отдадут вам True, если условие верно, и False, если условие не верно. Функции CompareStr, CompareText, TStringHelper.Compare, TStringHelper.CompareTo, TStringHelper.CompareOrdinal и TStringHelper.CompareText работают по-другому. Они сравнивают строки с точки зрения сортировки. Функции возвращают отрицательное число, если строка, указанная в первом параметре, сортируется до строки, указанной во втором параметре, положительное число — если первая строка сортируется после второй и 0 – если строки равны.

Функции SameStr, SameText, TStringHelper.Equals и TStringBuilder.Equals сравнивают строки на соответствие.

Итак, вот примеры использования вышеперечисленных функций и операторов:

Поиск подстроки в строке

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

В первую очередь – это функция Pos, которая ищет подстроку, начиная с указанного номера символа. Функция осуществляет регистрозависимый поиск. Здесь нумерация символов начинается с 1. Если подстрока найдена, то возвращается номер первого символа найденной подстроки, иначе – 0. Есть также функция PosEx (в юните System.StrUtils), которая работает абсолютно также. Вот пример использования функции Pos:

Аналогично функции Pos работают и функции IndexOf и LastIndexOf помощника TStringHelper. Они также осуществляют регистрозависимый поиск. Функция IndexOf ищет подстроку (или символ) с начала и до конца строки, а функция LasIndexOf – наоборот, т.е. с конца и до начала. Если подстрока найдена, то функции возвращают индекс первого символа найденной подстроки в строке. Здесь нумерация символов начинается с 0. Если подстрока не найдена, то функции возвращают -1. Также при поиске вы можете задать начало и интервал поиска. Вот примеры использования этих функций:

Теперь рассмотрим функции для проверки, есть ли подстрока в строке, и не важно, в каком месте. Для этого есть функции ContainsStr и ContainsText в юните System.StrUtils, а также функция Contains в помощнике TStringHelper.Contains. Функции ContainsStr и TStringHelper.Contains – регистрозависимые, а функция ContainsText – нет. Вот примеры использования этих функций:

Дополнительно есть функции проверяющие, наличие определённой подстроки в начале или в конце текста. Это функции StartsStr, StartsText, EndsStr и EndsText в юните System.StrUtils, а также функции StartsWith, EndsWith и EndsText у помощника TStringHelper. Функции StartsStr и EndsStr регистрозависимые, функции StartsText, EndsText и TStringHelper.EndsText регистронезависимые, а у функций TStringHelper.StartsWith и TStringHelper.EndsWith есть второй параметр для выбора режима поиска. Учтите, что регистронезависимый поиск в функции TStringHelper.StartsWith работает только с буквами латинского алфавита. По умолчанию поиск в функциях TStringHelper.StartsWith и TStringHelper.EndsWith регистрозависимый.

Обратите внимание, что регистронезависимый поиск в функциях StartsText, EndsText и TStringHelper.EndsText и TStringHelper.EndsWith ведётся для текущей локали. Т.е. если на компьютере будет установлена английская локаль, то регистронезависимый поиск по русскому тексту работать не будет.

Вот примеры использования функций:

И конечно самые продвинутые условия для поиска подстрок можно задавать при помощи регулярных выражений. Для этого есть функции TRegEx.Match и TRegEx.Matches. Вот несколько примеров использования этих функций:

Примеры и описание регулярных выражений смотрите на сайте библиотеки PCRE.

Поиск символов в строке

Случается, что нужно найти определённые символы в строке. Конечно, для этого вы можете воспользоваться функциями для поиска подстроки, о которых было написано выше, но есть и специальные функции, позволяющие найти первый попавшийся в строке символ из нескольких искомых. Это функции помощника TStringHelper: IndexOfAny, IndexOfAnyUnquoted и LastIndexOfAny. Функции IndexOfAny и IndexOfAnyUnquoted ищут, перебирая символы сначала до конца строки, а функция LastIndexOfAny – наоборот. Во всех функциях можно указать интервал поиска. Функция IndexOfAnyUnquoted умеет игнорировать символы, заключенные в кавычки, скобки и т.п. Вот пример использования этих функций:

Замена подстроки в строке

Для поиска и замены подстроки (или символа) в строке можно использовать функции StringReplace, ReplaceStr и ReplaceText, TStringHelper.Replace, TStringBuilder.Replace и TRegEx.Replace. Функции ReplaceStr и TStringBuilder.Replace – регистрозависимые, функция ReplaceText – регистронезависимая, в функциях StringReplace, TStringHelper.Replace и TRegEx.Replace зависимость от регистра настраивается флажком rfIgnoreCase. Функции TRegEx.Replace ищут подстроку, используя регулярные выражения. В функции TStringBuilder.Replace можно задать диапазон поиска подстроки. Вот примеры использования этих функций:

Обрезка пробелов и управляющих символов

Для такой часто встречающейся операции, как удаление пробелов и управляющих символов в начале и в конце строки, есть несколько функций: Trim, TrimLeft, TrimRight, TStringHelper.Trim, TStringHelper.TrimLeft и TStringHelper.TrimRight. При вызове функций TStringHelper.Trim, TStringHelper.TrimLeft и TStringHelper.TrimRight вы можете перечислить, какие символы нужно удалять. Вот пример использования этих функций:

Выравнивание текста за счёт установки пробелов

И напоследок ещё пара интересных функций, которые умеют дополнять строку пробелами или другими символами, пока она не станет нужной длины. Это функции TStringHelper.PadLeft и TStringHelper.PadRight. С помощью этих функций, например, для лучшего восприятия можно добавить пробелы в начало чисел, которые вы выдаёте столбиком в консоли или дополнить числа ведущими нулями. Вот пример использования этих функций:

Вместо заключения

Итак, в статье я постарался собрать все возможные функции Delphi, которые постоянно нужны при работе со строками. Надеюсь, вы найдёте в этой статье что-то новое и интересное для себя. Если я упустил что-то важное на ваш взгляд, просьба не держать это в себе, а написать об этом в комментариях.

Структурные типы данных: Строки

Структурные типы данных объединяют в себе один или несколько других типов, в том числе структурных. К структурным типам относятся:

Рассмотрим подробнее перечисленные типы.

Строки

Строки (строковые типы) представлены тремя физическими и одним общим типами.

ShortString ? максимальная длина символов — 255 ? Память 2 — 256 байт;

AnsiString ?Примерно 2 x 10 в 31 степени ? 4 байта — 2 Гбайт

WideString ?Примерно 2 х 10 в 30 степени ?4 байта — 2 Гбайт

Тип ShortString представляет собой строку, которая фактически является массивом из 256 элементов — array [0. .255]. Нулевой байт этого массива (строки) указывает длину строки. В ранних версиях языка подобная строка обозначалась типом string, тип shortstring введен в Object Pascal для обеспечения совместимости с этими версиями.

Язык Delphi поддерживает также подтипы типа shortstring, максимальная длина которых изменяется в диапазоне от 0 до 255 символов. Они обозначаются целым числом в квадратных скобках, указываемым справа от ключевого слова string. Например, инструкции:

обеспечивают объявление строковой переменной с именем str50, максимальная длина которой составляет 51 символ, т.е. столько, сколько требует описание типа, плюс 1 байт. В случае использования предопределенного типа shortstring мы израсходовали бы 256 байт памяти.

Типы AnsiString и WideString представляют собой динамические массивы, максимальная длина которых фактически ограничена размером основной памяти компьютера. В типе AnsiString для символов используется кодировка ANSI, а в типе WideString — кодировка Unicode.

Общим типом является тип String, который может соответствовать как типу ShortString, так и типу AnsiString, что определяется директивой компилятора $H. По умолчанию используется <$H+>, и тип String равен типу AnsiString. В файле параметров проекта знак «+» директивы (это верно и для других директив) соответствует записи H=1, а знак «-» — записи H=0. Разработчик обычно управляет интерпретацией типа String с помощью окна параметров проекта, устанавливая/снимая флажок Huge Strings (Большие строки).

Так как строки фактически являются массивами символов, для обращения к отдельному символу строки достаточно указать имя строковой переменной и номер (позицию) этого символа в квадратных скобках, например, strName [1].

Кроме рассмотренных, в языке имеется тип PChar, представляющий так называемук строку с нулевым окончанием— в ее конце стоит код #0. Максимальная длина этой строки ограничена размером основной памяти компьютера.

Илон Маск рекомендует:  Что такое код ncurses_assume_default_colors
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL