Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Быстрое сравнение строк


Автор: delphixxx 28.3.2006, 19:59
Всем привет.

Меня интересует функция сравнения двух спецыфических
строк.

строки выглядят примерно так: '541/45/63'
(цыфра разделитель, цыфра разделитель, цыфра разделитель)
числовые значения перед разделитетлем и после, могут быть любой величины.

Нужно сравнить две строки и определить какая больше
по принцыпу как с типом TDateTime


Пример :

X1 = 2:145:165
X2 = 4:200:399
X3 = 1:500:660

X1 > X3
X2 > X1
X2 > X3

Вот и желателбно чтобы это было на ассемблере так как в моём проекте очень важна скорость.





Автор: Демо 28.3.2006, 21:42
Цитата(delphixxx @ 28.3.2006, 19:59 Найти цитируемый пост)
Вот и желателбно чтобы это было на ассемблере так как в моём проекте очень важна скорость.


С чего ты взял, что на ассемблере быстрее будет?

Код

var
  s1,s2: String;
begin
  s1 := '2:145:165';
  s2 := '1:500:660';
  if s1>s2 then ShowMessage('s1>s2');


Автор: Guedda 28.3.2006, 21:54
Интересно. Я написал код, который написал Демо, но message не появилось... Немного исправив, появилась мессага, типа эти строки равны.
Вообще по определению такое сравнение ведет к побайтовому сравнению... Сколько байт занято...

Автор: delphixxx 28.3.2006, 23:14
Демо,
не всё так просто как вы думаете, тут полюбому нужно разбивать строки и сравнивать цыфры, ибо
если дейсвовать по вашему методу то например '12' < '4' .

Автор: Демо 29.3.2006, 11:43
Цитата(delphixxx @ 28.3.2006, 23:14 Найти цитируемый пост)
не всё так просто как вы думаете, тут полюбому нужно разбивать строки и сравнивать цыфры, ибо
если дейсвовать по вашему методу то например '12' < '4' .


А где было написано, что значность может быть разная?

В приведенном в топике примере было видно четкое форматирование.

Автор: Guedda 29.3.2006, 11:46
Тогда просто необходимо парсить строки, переводить в Integer и сравнивать. По другому, никак.

Автор: RA 29.3.2006, 15:19
Цитата(Демо @ 29.3.2006, 11:43 Найти цитируемый пост)
А где было написано, что значность может быть разная?


Цитата(delphixxx @ 28.3.2006, 19:59 Найти цитируемый пост)
числовые значения перед разделитетлем и после, могут быть любой величины.

smile

Автор: Демо 29.3.2006, 15:50
RAdmin,
А-а, тогда понятно.

Автор: Romikgy 29.3.2006, 16:41
Код

var
  s1,s2: String;
i: integer;
begin
  s1 := '2:145:165';
  s2 := '1:500:660';
  i:=AnsiStrComp(Pchar(s1),Pchar(s2));
  if i>0 then ShowMessage('s1>s2')
else if i<0 then ShowMessage('s1<s2')
else ShowMessage('s1=s2');



А так не?

Автор: Digitalator 29.3.2006, 16:56
а если
s1 := '2:1450:165';
s2 := '12:500:660';

надо разбивать строки на числа и сравнивать ... на асме такое писать неинтересно smile

Автор: Digitalator 29.3.2006, 17:29
пример на неасме
Код

//константа - разделитель
const schar : char = ':';
//функция для разбивки строк, возвращает true если удалось отделить подстроку, обрезает исходную строку
function sxpld(var s, substr : string) : boolean;
  var vpos : integer;
  begin
  vpos := pos(schar, s);
  if length(s) = 0 then
    begin
    result := false;
    exit;
    end;
  result := true;
  if vpos > 0 then
    begin
    substr := copy(s, 1, vpos-1);
    if length(substr) = 0 then
      begin
      result := false;
      exit;
      end;
    s:=copy(s, vpos+1, length(s)-vpos);
    end else begin
    substr := s;
    s := '';
    end;
  end;
//Функция для сравнения возвращает 0 если строки равны, 1 если больше строка 1, 2 если больше строка 2.
//если не возникло ошибок, то code = 0
function scmp(s1, s2 : string; var code : integer) : integer;
  var str : string;
      ds1, ds2 : array[1..3] of string;
      di1, di2 : array[1..3] of integer;
      i : integer;

  begin
  code := 0;
  result := 0;
  //Разбиваем первую строку
  str := s1;
  for i := 1 to 3 do
   if not sxpld(str, ds1[i]) then
      begin
      code := -1;
      exit;
      end;
  if length(str) > 0 then
    begin
    code := -1;
    exit;
    end;
  //Разбиваем вторую строку
  str := s2;
  for i := 1 to 3 do
   if not sxpld(str, ds2[i]) then
      begin
      code := -1;
      exit;
      end;
  if length(str) > 0 then
    begin
    code := -1;
    exit;
    end;
  //Преобразуем строки в целый тип
  for i := 1 to 3 do
    begin
    val(ds1[i], di1[i], code);
    if code <> 0 then exit;
    val(ds2[i], di2[i], code);
    if code <> 0 then exit;
    end;
  //сравниваем
  i:=1;
  while i<=3 do
    begin
    if di1[i] > di2[i] then
      begin
      result := 1;
      exit;
      end;
    if di2[i] > di1[i] then
      begin
      result := 2;
      exit;
      end;
    inc(i);
    end;
  end;

{$R *.dfm}
//пример сравнения
procedure TForm1.Button1Click(Sender: TObject);
var res, code : integer;
    str : string;
begin
res := scmp(edit1.Text, edit2.Text, code);
if code = 0 then
 begin
 case res of
   0: str:='строки равны';
   1: str:='строка 1 больше';
   2: str:='строка 2 больше';
   end;
 label1.Caption := str;
 end else label1.Caption := 'ошибка сравнения');
end;

Автор: Snowy 29.3.2006, 18:43
Вот, нарисовал простое, элегантное решение:
Код
function CompDigStr(s1, s2: string): integer;
  function ModStr(s:string): string;
  var
    i: integer;
    c: integer;
  begin
    c := 0; result := s;
    for i := Length(s) downto 1 do
      if s[i] = ':' then begin
        insert(chr(c+48), result, i+1);
        c := 0;
      end else inc(c);
    result := chr(c+48) + result;
  end;
begin
  result := CompareStr(ModStr(s1), ModStr(s2));
end;
Возвращает -1, если s1<s2; 0, если s1=s2; 1, если s1>s2

Пример:
Код
  ShowMessage(IntToStr(CompDigStr('2:1450:165','12:500:660')));

Автор: delphixxx 29.3.2006, 21:02
Snowy, Спасибо smile

Автор: Digitalator 31.3.2006, 08:10
Цитата(Snowy)
Возвращает -1, если s1<s2; 0, если s1=s2; 1, если s1>s2

не совсем так
Цитата(Delphi Help)
CompareStr compares S1 to S2, with case-sensitivity. The return value is less than 0 if S1 is less than S2, 0 if S1 equals S2, or greater than 0 if S1 is greater than S2. The compare operation is based on the 8-bit ordinal value of each character and is not affected by the current locale.


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

Автор: Guedda 31.3.2006, 22:21
Нужно быстро и на асме?
Бери:
Код

function CompareStr(const S1, S2: string): Integer; assembler;
asm
          PUSH    ESI
          PUSH    EDI
          MOV     ESI,EAX
          MOV     EDI,EDX
          OR      EAX,EAX
          JE      @@1
          MOV     EAX,[EAX-4]
@@1:    OR      EDX,EDX
          JE      @@2
          MOV     EDX,[EDX-4]
@@2:    MOV     ECX,EAX
          CMP     ECX,EDX
          JBE     @@3
          MOV     ECX,EDX
@@3:    CMP     ECX,ECX
          REPE    CMPSB
          JE      @@4
          MOVZX   EAX,BYTE PTR [ESI-1]
          MOVZX   EDX,BYTE PTR [EDI-1]
@@4:    SUB     EAX,EDX
          POP     EDI
          POP     ESI
end;

Автор: Snowy 1.4.2006, 10:23
Guedda, а зачем выкладывать код CompareStr?
Можно было просто сказать, что она написана на асме.

Автор: Guedda 1.4.2006, 10:35
Ну так в качестве доказательства. Вдруг человек не поверит?

Автор: Snowy 1.4.2006, 10:40
smile
Вобщем вопрос решен.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)