:: MVP ::
|
|
:: RSS ::
|
|
|
Сортируя строки обычным (применяя для сравнения операторы ">", "<" или “=”) методом, получаемый результат не всегда
является логичным с точки зрения человека. Речь идет о тех случаях, когда строки содержат в себе числа. Допустим,
у нас есть набор из следующих строк: ‘str_1’, ‘str_8’, ‘str_11’, ‘str_19’, ‘str_2’ и ‘str_20’. Ниже, в таблице,
приведен пример того, как эти строки будут отсортированы обычным способом (в левой колонке), и как бы это было
естественнее для восприятия человеком (в правой колонке).
Обычная сортировка |
Чего бы хотелось |
str_1 |
str_1 |
str_11 |
str_2 |
str_19 |
str_8 |
str_2 |
str_11 |
str_20 |
str_19 |
str_8 |
str_20 |
Как же это сделать? Попробуем разобраться
function StrCmpDig( const Str1, Str2: string ): Integer;
var
i, Len, Digit1, Digit2, DigitLen1, DigitLen2: Integer;
begin
if Trim( Str1 ) = Trim( Str2 ) then Exit( 0 );
if ( Str1 = '' ) then Exit( -1 );
if ( Str2 = '' ) then Exit( 1 );
Len := Max( Length( Str1 ), Length( Str2 ) );
i := 1;
while i <= Len do
begin
if IsDigit( Str1[i] ) and ( IsDigit( Str2[i] ) ) and ( Str1[i] <> '0' ) and ( Str2[i] <> '0' ) then
begin
DigitLen1 := DigitLen( Str1, i );
DigitLen2 := DigitLen( Str2, i );
Digit1 := StrToInt( Copy( Str1, i, DigitLen1 ) );
Digit2 := StrToInt( Copy( Str2, i, DigitLen2 ) );
if Digit1 < Digit2 then Exit( -1 );
if Digit1 > Digit2 then Exit( 1 );
Inc( i, Min( DigitLen1, DigitLen2 ) );
Continue;
end;
if Str1[i] < Str2[i] then Exit( -1 );
if Str1[i] > Str2[i] then Exit( 1 );
Inc( i );
end;
Result := 0;
end;
|
Первые 3 строчки кода обрабатывают ситуацию, когда приходится иметь дело с пустыми строками.
В случае, если заранее известно, что пустых строк в вашем приложении не будет, их можно убрать.
Запускаем цикл с числом итераций рамным длине самой большой строки. Если в одинаковой позиции в
обеих строках находим цифру, то получаем число, находящееся в строках начиная с этой позиции. И
та строка, число в которой окажется больше, и будет больше, все просто!
Часть первоначального условия
{...} and ( Str1[i] <> '0' ) and ( Str2[i] <> '0' ) then
|
нужна для того, чтобы корректно обрабатывать ситуации, в которых число в одной из строк начинается с нуля,
например ‘num_01’ и ‘num_11’.
Параметризированный Exit появился в Delphi 2009, для более ранних версий нужно писать
begin
Result := -1;
Exit;
end;
|
Длину числа в строке определяем следующим образом.
function DigitLen( Str: string; Index: Integer ): Integer;
var
i: integer;
begin
Result := 0;
for i := Index to Length( Str ) do
if IsDigit( Str[i] ) then
Inc( Result )
else
Break;
end;
|
Функцию проверки символа на равенство числу можно написать самостоятельно,
function IsDigit( c: Char ): Boolean;
begin
Result := ( c >= '0' ) and ( c <= '9' );
end;
|
а можно воспользоваться классом TCharacter.
uses
{...,} Character;
if TCharacter.IsDigit( c ) then {...}
|
В прилагаемом примере реализовано 2 типа сортировки на базе ListView, наглядно демонстрирующих
удобство описанного в статье метода. Применение этого метода сортировки в ваших программах благоприятно
скажется на отношении к ним пользователей. Удачи в программировании!
.: Пример к данной статье :.
|
При использовании материала - ссылка на сайт обязательна
|
|