Всем привет,
У меня есть небольшой код на PHP, который я хотел бы преобразовать в Delphi, и у меня есть некоторые проблемы …
Вот код PHP:
$from = "121.198.0.0"; $to = "121.198.255.255"; $arry1 = explode(".", $from); $arry2 = explode(".", $to); $a1 = $arry1[0]; $b1 = $arry1[1]; $c1 = $arry1[2]; $d1 = $arry1[3]; $a2 = $arry2[0]; $b2 = $arry2[1]; $c2 = $arry2[2]; $d2 = $arry2[3]; while ($d2 >= $d1 || $c2 > $c1 || $b2 > $b1 || $a2 > $a1) { if ($d1 > 255) { $d1 = 1; $c1++; } if ($c1 > 255) { $c1 = 1; $b1++; } if ($b1 > 255) { $b1 = 1; $a1++; } echo "$a1.$b1.$c1.$d1<br>"; $d1++; }
И в Delphi я начал с этого:
procedure TForm1.Button1Click(Sender: TObject); var Arry1, Arry2: TStringList; RangeFrom, RangeTo: string; a1, b1, c1, d1, a2, b2, c2, d2: string; begin RangeFrom := Edit1.Text; RangeTo := Edit2.Text; Arry1 := Explode('.', RangeFrom); Arry2 := Explode('.', RangeTo); a1 := Arry1[0]; b1 := Arry1[1]; c1 := Arry1[2]; d1 := Arry1[3]; a2 := Arry1[0]; b2 := Arry1[1]; c2 := Arry1[2]; d2 := Arry1[3]; while (StrToInt(d2) >= StrToInt(d1)) //and StrToInt(c2) > (StrToInt(c1) //and StrToInt(b2) > (StrToInt(b1) //and StrToInt(a2) > (StrToInt(a1) do begin if (StrToInt(d1) > 255) then begin d1 := '1'; StrToInt(c1)+1; end; if (StrToInt(c1) > 255) then begin c1 := '1'; StrToInt(b1)+1; end; if (StrToInt(b1) > 255) then begin b1 := '1'; StrToInt(a1)+1; end; ListBox1.Items.Add(a1+'.'+b1+'.'+c1+'.'+d1); StrToInt(d1)+1; end; end;
(Для функции Explode я использую: http://www.marcosdellantonio.net/2007/06/14/funcao-explode-do-php-em-delphi/ )
Кто-то может помочь мне сделать этот небольшой код в Delphi?
Заранее спасибо 🙂
Beny
Вот что я вижу, просто просматривая код:
Если вы думаете, что у вас есть параметры Explode
в неправильном порядке. Сепаратор является вторым параметром в функции, с которой вы связаны. Поэтому вы должны написать:
Arry1 := Explode(RangeFrom, '.'); Arry2 := Explode(RangeTo, '.');
Вы пропускаете память, не освобождая массивы, возвращаемые функцией Explode
. Delphi отличается от PHP тем, что вам часто приходится управлять памятью объектов, которые вы создаете.
a2 := Arry1[0]; b2 := Arry1[1]; c2 := Arry1[2]; d2 := Arry1[3];
Это должен быть Arry2
а не Arry1
.
Вы должны преобразовать строки в целые числа вперед. Поэтому объявите их следующим образом:
a1, b1, c1, d1, a2, b2, c2, d2: Integer;
и напишите присваивания следующим образом:
a1 := StrToInt(Arry1[0]); b1 := StrToInt(Arry1[1]); //etc. etc.
while ($d2 >= $d1 || $c2 > $c1 || $b2 > $b1 || $a2 > $a1)
переводит на:
while ((d2 >= d1) or (c2 > c1) or (b2 > b1) or (a2 > a1))
Внутри цикла while вам нужен такой код:
if d1 > 255 then begin d1 := 1; inc(c1); end;
Преобразование 4 значений обратно в IP-адрес проще всего с помощью функции Format
:
ListBox1.Items.Add(Format('%d.%d.%d.%d', [a1, b1, c1, d1]));
У вас есть неправильное понимание того, что StrToInt
это функция, которая получает в качестве входных данных строку и возвращает целое число. Когда вы пишете:
StrToInt(d1)+1
вы не изменяете переменную d1
которая является только входной переменной. Эта проблема исчезает, когда вы делаете другие изменения, которые я описываю, но я хотел указать на вашу будущую выгоду.
Вы также можете заставить периодическую перерисовку окна списка, чтобы вы могли видеть, что происходит.
Поместите все это вместе, и у вас есть это:
var Arry1, Arry2: TStringList; RangeFrom, RangeTo: string; Count: Integer; a1, b1, c1, d1, a2, b2, c2, d2: Integer; begin RangeFrom := Edit1.Text; RangeTo := Edit2.Text; Arry1 := Explode(RangeFrom, '.'); try a1 := StrToInt(Arry1[0]); b1 := StrToInt(Arry1[1]); c1 := StrToInt(Arry1[2]); d1 := StrToInt(Arry1[3]); finally Arry1.Free; end; Arry2 := Explode(RangeTo, '.'); try a2 := StrToInt(Arry2[0]); b2 := StrToInt(Arry2[1]); c2 := StrToInt(Arry2[2]); d2 := StrToInt(Arry2[3]); finally Arry2.Free; end; Count := 0; while ((d2 >= d1) or (c2 > c1) or (b2 > b1) or (a2 > a1)) do begin if d1 > 255 then begin d1 := 1; inc(c1); end; if c1 > 255 then begin c1 := 1; inc(b1); end; if b1 > 255 then begin b1 := 1; inc(a1); end; ListBox1.Items.Add(Format('%d.%d.%d.%d', [a1, b1, c1, d1])); inc(Count); if Count mod 1000=0 then begin ListBox1.Repaint; ListBox1.TopIndex := ListBox1.Items.Count-1; end; inc(d1); end; end;
Я думаю, что причина в том, что он ничего не делает прямо сейчас, вы не можете иметь никаких значений в edit1.text или edit2.text.
Для тестирования (прежде чем делать этот фрагмент процедурой или функцией) вы можете просто назначить некоторые тестовые данные RangeFrom и RangeTo.
Ex. RangeFrom: = '121.198.0.0'; RangeTo: = '121.198.255.255';
Тестирование цели:
procedure TForm1.Button1Click(Sender: TObject); var AddrList: TStringList; StartAddress, EndAddress: Cardinal; a, b, c, d: PByte; x: Cardinal; begin AddrList := TStringList.Create; AddrList.Delimiter := '.'; AddrList.DelimitedText := Edit1.Text; StartAddress := (Cardinal(StrToInt(AddrList.Strings[0])) shl 24 ) + (Cardinal(StrToInt(AddrList.Strings[1])) shl 16) + (Cardinal(StrToInt(AddrList.Strings[2])) shl 8) + StrToInt(AddrList.Strings[3]); AddrList.DelimitedText := Edit2.Text; EndAddress := (Cardinal(StrToInt(AddrList.Strings[0])) shl 24 ) + (Cardinal(StrToInt(AddrList.Strings[1])) shl 16) + (Cardinal(StrToInt(AddrList.Strings[2])) shl 8) + StrToInt(AddrList.Strings[3]); AddrList.Free; for x := StartAddress to EndAddress do begin a := @x; b := a; Inc(a); c := a; Inc(a); d := a; Inc(a); Memo1.Lines.Add(Format('%d.%d.%d.%d', [a^,d^,c^,b^])); end; end;