Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Книга о KOL.doc
Скачиваний:
29
Добавлен:
30.04.2019
Размер:
1.77 Mб
Скачать

2.12. Списки строк в kol (tStrList, tStrListEx и другие)

Разумеется, списки строк - это очень удобная разновидность объектов для хранения строк произвольного размера. В KOL они так же присутствуют, и называются TStrList и TStrListEx. Но в KOL эти списки не используются для виртуализации доступа к строкам в Memo или RichEdit. Важное отличие от TStrings в VCL: строки не могут содержать символ #0, так как строки хранятся именно как цепочки символов, завершенные байтом с кодом #0. Это продиктовано соображениями скорости работы с большими текстами. Загрузка текста (например, из файла) в объект TStrList, или сохранение текста в файл или поток - это чрезвычайно быстрая операция, и выполняется мгновенно даже для мегабайтов и десятков мегабайт.

Объект TStrListEx отличается от своего предка TStrList (один из редких случаев в KOL, когда объектный тип наследуется не напрямую от TObj) тем, что имеет свойство Objects, сопоставляющее каждой строке 32-разрядное число, или указатель (фактически, TStrListEx строится как объединение TStrList и TList, и операции над их элементами производятся синхронно).

Для создания списков строк используются функции-"конструкторы":

NewStrList - создает объект типа TStrList, возвращает указатель на него типа PStrList;

NewStrListEx - создает объект TStrListEx, возвращает указатель типа PStrListEx.

Основной набор методов и свойств, характерный для TStrList:

Count - количество строк в списке;

Add( s ) - добавляет строку в конец списка;

Insert( i, s ) - вставляет строку в позицию i;

AddStrings( SL ) - добавляет в конец списка все строки из другого объекта типа PStrList;

Assign( SL ) - присваивает данному списку строк содержимое списка строк, заданного параметром;

Clear - очищает список, освобождая память, занятую строками;

Delete( i ) - удаляет строку с индексом i;

DeleteLast - удаляет последнюю строку в списке;

IndexOf( s ) - находит строку s в списке (регистр учитывается), и возвращает индекс найденной строки, или -1, если строка не найдена;

IndexOf_NoCase( s ) - то же, что и предыдущий метод, но поиск заданной строки идет без учета регистра (имеется в виду регистр кодировки Ascii, регистр национальных символов проигнорирован этим методом быть не может);

IndexOfStrL_NoCase( s, n ) - то же, что и предыдущий метод, но сравнивается только n первых символов строки;

Find( s, i ) - выполняет поиск в отсортированном списке (используется метод деления пополам, что увеличивает скорость поиска в больших списках строк);

Items[ i ] - данное свойство обеспечивает доступ к отдельным элементам списка как к Ansi-строкам, и позволяет их читать или модифицировать;

Last - свойство для доступа к последней строке в списке (эквивалентно Items[ Count-1 ])

ItemPtrs[ i ] - данное свойство, в отличие от Items, позволяет получить адрес начала строки списка по ее индексу. Для целей чтения строк или модификации их на месте этот способ предпочтительней в плане быстродействия, так как не требуется выделение в куче памяти для копии строки. Разумеется, при модификации строк "на месте" требуется контролировать возможный выход за пределы строки при записи в нее, иначе гарантировано возникновение неприятных последствий. Вплоть до немедленного краха приложения или возникновения исключения доступа к памяти - Access Violation, или, что хуже, к порче служебных полей менеджера кучи, и последующему краху приложения, причины которого гораздо сложней поддаются идентификации и исправлению;

Sort( casesensitive ) - сортирует строки (после чего можно применять метод Find, например);

AnsiSort( casesensitive ) - сортирует строки как ANSI (т.е. учитывается так же порядок национальных символов);

Swap( i1, i2 ) - обменивает местами строки в списке;

Move( i1, i2 ) - перемещает строку с индексом i1 в позицию i2;

Text - обеспечивает возможность работать со всеми строками списка как с одной строкой. При чтении этого свойства все строки - быстро - объединяются в один текст, состоящий из строк текста, разделенных символами #13#10, при присваивании значения этому свойству исходная большая строка - быстро - разделяется на отдельные строки по признаку наличия комбинаций символов #13#10, #13, #0 в конце каждой подстроки. Важная деталь: сразу после присваивания значения этому свойству все строки в списке хранятся в непрерывном участке памяти, одна за другой, завершаясь каждая байтом #0. Это обстоятельство возможно использовать для того, чтобы выполнять быструю обработку больших текстов (получив указатель на первую строку, с индексом 0, через свойство ItemPtrs[ 0 ], далее можно указателем "пробежать" все строки, считая количество завершающих байтов #0 до достижения счетчиком значения Count);

SetText( s, append ) - дополнительный метод, позволяет быстро добавить текст из единой строки разбивая его на строки примерно так же, как это делается при присваивании свойству Text;

SetUnixText( s, append ) - аналогично предыдущему, но в качестве разделителей, в том числе рассматриваются и одиночные символы #10 (стандарт для Unix-систем);

Join( s ) - функция, которая возвращает объединение строк наподобие того, как это делает свойство Text, но межстрочный разделитель задается параметром.

В особую группу можно выделить набор методов для обмена данными с файлами и потоками данных:

LoadFromFile( s ) - загружает список строк из текстового файла;

SaveToFile( s ) - сохраняет список строк как текст в файле;

LoadFromStream( strm ) - загружает список строк из потока (читая его с текущей позиции и до конца потока);

SaveToStream( strm ) - сохраняет список строк в поток (записывая его с текущей позиции в потоке);

AppendToFile( s ) - дозаписывает строки из списка в конец указанного файла;

MergeFromFile( s ) - добавляет к списку строк строки из указанного файла;

Список строк может использоваться специальным образом как набор именованных значений вида <имя_значения>=<значение> (аналогично Ini-файлам), причем в качестве знака, отделяющего имя значения от самого значения, может использоваться не только символ '=', но и, например, символ ':', и любой другой символ. При создании списка для инициализации разделителя используется символ, заданный глобальной переменной DefaultNameDelimiter, по умолчанию хранящий значение '='. Можно либо изменить значение этой переменной до создания списка, либо изменить свойство NameDelimiter каждого отдельного списка. Далее перечислю методы и свойства для работы со списком строк как со списком значений:

Values[ s ] - это свойство позволяет прочитать или изменить значение с именем s (если при чтении имя не обнаружено, возвращается пустая строка, если при записи имя еще не существует, оно добавляется);

IndexOfName( s ) - возвращает индекс строки, содержащей значение с указанным именем;

LineName[ i ] - возвращает или изменяет (при записи) имя в строке с индексом i;

LineValue[ i ] - аналогично для значения в строке с индексом i.

Объектный тип TStrListEx, являясь наследником типа TStrList, сохраняет все эти возможности, и добавляет к ним возможность связывать каждую строку в списке с числовым значением, или указателем - по желанию. Ввиду того, что политика наследования и злоупотребление виртуальными методами не приветствуется в KOL, не следует использовать полиморфизм параметров-объектов, и работать с TStrListEx как с объектом TStrList. Страшного ничего не случится (скорее всего), но при удалении строк, изменении их порядка и прочих операциях, согласование между строками и ассоциированными с ними "объектами", скорее всего, будет нарушено. Вывод из сказанного: если уж вы используете объект типа TStrListEx, то этот объект в любом коде, который с ним работает, должен быть объявлен именно как TStrListEx.

Все вышеприведенные методы объекта TStrList имеют место и для TStrListEx, но если не используются специализированные аналоги, разработанные для TStrListEx, то объект предполагается нулевой (т.е. при вызове Insert( i, s ) в позицию i будет вставлена строка, а в качестве ее объекта будет вставлено, так же в позицию i, значение 0). Далее приведу список методов и свойств, характерных именно для TStrListEx:

Objects[ i ] - доступ к объектам, ассоциированным со строками, по индексу строки;

LastObj - доступ к последнему "объекту", эквивалентен Objects[ Count-1 ];

Assign( SLex ) - присваивает строки и объекты из указанного расширенного списка строк;

AddObject( s, o ) - добавляет строку сразу с "объектом"-числом, с ним ассоциированным;

InsertObject( i, s, o ) - аналогично предыдущему, вставляет строку вместе с объектом, в позицию i;

IndexOfObj( o ) - находит первый объект o, и возвращает его индекс (или -1, если такой "объект" не найден).

Кроме приведенных объектных типов для хранения списков строк, в KOL имеются так же и другие (но они вынесены в дополнительный модуль KOLadd.pas): TFastStrListEx, TWStrList, TWStrListEx.

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

Объекты TWStrList и TWStrListEx аналогичны объектам TStrList и TStrListEx, но ориентированы на работу со строками Unicode (WideString), состоящими из двухбайтных символов (WideChar). Поэтому описывать их детально так же не имеет особого смысла, практически все сказанное для обычных списков строк, верно и для этих списков, кроме типа самих хранящихся в них строк.

В отличие от многих других объектов в KOL, при использовании директивы UNICODE_CTRL списки строк TStrList и TStrListEx автоматически не становятся списками UNICODE-строк. Для того, чтобы не вставлять в свой код директивы условной компиляции вида {$IFDEF UNICODE_CTRLS} … {$ELSE} … {$ENDIF}, в KOL декларирован типы TKOLStrList / TKOLStrListEx, эквивалентные TStrList / TStrListEx в случае использования Ansi строк, и заменяемый типами TWStrList / TWStrListEx в случае добавления символа условной компиляции UNICODE_CTRLS. Это нужно потому, что иногда в Ansi-приложениях требуется работать с UNICODE-текстом и (даже чаще) наоборот – в UNICODE-проекте обрабатывать «чистый» Ansi список строк.

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