===============================================
20110919 수정사항 추가

    else if Str1[Pos1] = #0 then
    begin
      Result := 0;
      Exit;
    end

에셔 결과값 0을 -1로 변경해야함.

================================================


---------
a - 1
a - 10
a - 99
a - 9
a - 10000
---------
위와 같은 데이터가 있을때

델파이의 CompareStr로 비교하면
---------
a - 1
a - 10
a - 10000
a - 9
a - 99
---------
로 나옵니다.

윈도우탐색기에서 입력해보면
--------
a - 1
a - 9
a - 10
a - 99
a - 10000
--------
으로 정렬됩니다.


출처는 http://www.scottandmichelle.net/scott/code/index2.mv?codenum=100 입니다.
씨 소스로 되어있길래 포팅해봤습니다.

function NaturalOrderCompareString( const A1, A2: string; ACaseSensitive: Boolean ): Integer;
var
  Str1, Str2: PChar;
  Pos1, Pos2: Integer;
  EndPos1, EndPos2: Integer;
begin
  Str1 := PChar(A1);
  Str2 := PChar(A2);

  Pos1 := -1;
  Pos2 := -1;

  while True do
  begin
    Inc( Pos1 );
    Inc( Pos2 );

    if (Str1[Pos1] = #0) and (Str2[Pos2] = #0) then
    begin
      Result := 0;
      Exit;
    end
    else if Str1[Pos1] = #0 then
    begin
      Result := -1;
      Exit;
    end
    else if Str2[Pos2] = #0 then
    begin
      Result := 1;
      Exit;
    end;

    if (Str1[Pos1] >= '0') and (Str1[Pos1] <= '9') and
       (Str2[Pos2] >= '0') and (Str2[Pos2] <= '9') then
    begin
      EndPos1 := Pos1;
      repeat
        Inc(EndPos1);
      until not ((Str1[EndPos1] >= '0') and (Str1[EndPos1] <= '9'));

      EndPos2 := Pos2;
      repeat
        Inc(EndPos2);
      until not ((Str2[EndPos2] >= '0') and (Str2[EndPos2] <= '9'));

      while True do
      begin
        if EndPos1 - Pos1 = EndPos2 - Pos2 then
        begin
          // 이부분이 숫자비교임. StrToInt 한 다음에 빼도 될 것임
          Result := CompareStr( Copy(Str1, Pos1+1, EndPos1 - Pos1),  Copy(Str2, Pos2+1, EndPos1 - Pos1) ) ;

          if Result = 0 then
          begin
            Pos1 := EndPos1 - 1;
            Pos2 := EndPos2 - 1;
            Break;
          end
          else
          begin
            Exit;
          end;
        end
        else if EndPos1 - Pos1 > EndPos2 - Pos2 then
        begin
          if Str1[Pos1] = '0' then
            Inc(Pos1)
          else
          begin
            Result := 1;
            Exit;
          end;
        end
        else
        begin
          if Str2[Pos2] = '0' then
            Inc( Pos2 )
          else
          begin
            Result := -1;
            Exit;
          end;
        end;
      end;
    end
    else
    begin
      if ACaseSensitive then
        Result := CompareStr( Copy(Str1, Pos1, 1), Copy(Str2, Pos2, 1) )
      else
        Result := CompareText( Copy(Str1, Pos1, 1), Copy(Str2, Pos2, 1) );

      if Result <> 0 then
        Exit;
    end;
  end;
end;



리스트뷰 OnCompare에 델파이의 CompareStr, NaturalOrderCompareString 함수, Windows 유닛 내의 CompareString 함수로 정렬해서 비교한 간단한 예제가 있으니 비교해보시기 바랍니다.

정렬부분 소스는
procedure TForm3.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
  Data: Integer; var Compare: Integer);
var
  CompareResult: Integer;
begin
  case ComboBox1.ItemIndex of
    0:
    begin
      // Na
      Compare := NaturalOrderCompareString( Item1.Caption, Item2.Caption, True );
    end;
    1:
    begin
      // 일반 문자열 비교
      Compare := CompareStr( Item1.Caption, Item2.Caption );
    end;
    2:
    begin
      // Window API
      CompareResult := CompareString( LOCALE_USER_DEFAULT, 0, PChar(Item1.Caption), Length(Item1.Caption), PChar(Item2.Caption), Length(Item2.Caption) );

      case CompareResult of
        CSTR_LESS_THAN:     Compare := -1;
        CSTR_GREATER_THAN:  Compare := 1;
        CSTR_EQUAL:         Compare := 0;
      end;
    end;
  end;
end;


+ Recent posts