Есть ли аналог sscanf в Delphi?

yolki

вот про аналог sprintf знаю..
шаз нужно распарсить такую строку:

22.5, 12.4, 400 ; комментарий

В С делается просто...

i=sscanf(buf,"%lf,%lf,%d;%s",&x,&y,&i,s);

как бы по-проще извернуться в паскале....

Werdna

не надо хотеть использовать говнопродукты типа дэлфи

yolki

Сам ты гавнопродукт

korsar0156

видимо еще не все гуглят перед тем как задавать глупые вопросы...
это первая ссылка, возможно бальше есть и поопрятнее решения:
 unit Scanf;
interface
uses SysUtils;
type
EFormatError = class(ExCeption);
function Sscanf(const s: string; const fmt : string;
const Pointers : array of Pointer) : Integer;
implementation
{ Sscanf parses an input string. The parameters ...
s - input string to parse
fmt - 'C' scanf-like format string to control parsing
%d - convert a Long Integer
%f - convert an Extended Float
%s - convert a string (delimited by spaces)
other char - increment s pointer past "other char"
space - does nothing
Pointers - array of pointers to have values assigned
result - number of variables actually assigned
for example with ...
Sscanf('Name. Bill Time. 7:32.77 Age. 8',
'. %s . %d:%f . %d', [@Name, @hrs, @min, @age]);
You get ...
Name = Bill hrs = 7 min = 32.77 age = 8 }
function Sscanf(const s: string; const fmt : string;
const Pointers : array of Pointer) : Integer;
var
i,j,n,m : integer;
s1 : string;
L : LongInt;
X : Extended;
function GetInt : Integer;
begin
s1 := '';
while (s[n] = ' ') and (Length(s) > n) do inc(n);
while (s[n] in ['0'..'9', '+', '-'])
and (Length(s) >= n) do begin
s1 := s1+s[n];
inc(n);
end;
Result := Length(s1);
end;
function GetFloat : Integer;
begin
s1 := '';
while (s[n] = ' ') and (Length(s) > n) do inc(n);
while (s[n] in ['0'..'9', '+', '-', '.', 'e', 'E'])
and (Length(s) >= n) do begin
s1 := s1+s[n];
inc(n);
end;
Result := Length(s1);
end;
function GetString : Integer;
begin
s1 := '';
while (s[n] = ' ') and (Length(s) > n) do inc(n);
while (s[n] <> ' ') and (Length(s) >= n) do
begin
s1 := s1+s[n];
inc(n);
end;
Result := Length(s1);
end;
function ScanStr(c : Char) : Boolean;
begin
while (s[n] <> c) and (Length(s) > n) do inc(n);
inc(n);
If (n <= Length(s then Result := True
else Result := False;
end;
function GetFmt : Integer;
begin
Result := -1;
while (TRUE) do begin
while (fmt[m] = ' ') and (Length(fmt) > m) do inc(m);
if (m >= Length(fmt then break;
if (fmt[m] = '%') then begin
inc(m);
case fmt[m] of
'd': Result := vtInteger;
'f': Result := vtExtended;
's': Result := vtString;
end;
inc(m);
break;
end;
if (ScanStr(fmt[m]) = False) then break;
inc(m);
end;
end;
begin
n := 1;
m := 1;
Result := 0;
for i := 0 to High(Pointers) do begin
j := GetFmt;
case j of
vtInteger : begin
if GetInt > 0 then begin
L := StrToInt(s1);
Move(L, Pointers[i]^, SizeOf(LongInt;
inc(Result);
end
else break;
end;
vtExtended : begin
if GetFloat > 0 then begin
X := StrToFloat(s1);
Move(X, Pointers[i]^, SizeOf(Extended;
inc(Result);
end
else break;
end;
vtString : begin
if GetString > 0 then begin
Move(s1, Pointers[i]^, Length(s1)+1);
inc(Result);
end
else break;
end;
else break;
end;
end;
end;
end.

korsar0156

Во, от джедаев покрасивее ftp://delphi-jedi.org//tools/sscanf.zip

yolki

Ок, я неправильно сформулировал вопрос..
надо было так:
Есть ли встроенный аналог...
Коль скоро люди пишут самопальные функции, значит нет.. печально.
да, и поинтеры - это беее..

garikus

Ну.. я обычно такие простые сам пишу быстро
	PROCEDURE Parse (IN s: ARRAY OF CHAR; OUT x1, x2, x3: REAL; OUT c: ARRAY OF CHAR; OUT res: INTEGER);
VAR ch: CHAR; i: INTEGER;

PROCEDURE Get;
BEGIN
IF i < LEN(s) THEN ch := s[i]; INC(i)
ELSE ch := 0X
END
END Get;

PROCEDURE Real (OUT x: REAL);
VAR str: ARRAY 20 OF CHAR; i: INTEGER;
BEGIN
IF res # 0 THEN RETURN END;
i := 0;
IF (ch = '-') OR (ch = '+') THEN
str[i] := ch; INC(i); Get
END;
WHILE (ch >= '0') & (ch <= '9') DO
str[i] :=ch; INC(i); Get
END;
IF ch = '.' THEN str[i] := ch; INC(i); Get END;
WHILE (ch >= '0') & (ch <= '9') DO
str[i] :=ch; INC(i); Get
END;
IF i = 0 THEN res := 100
ELSE str[i] := 0X;
Strings.StringToReal(str, x, res)
END
END Real;

PROCEDURE Expect (ech: CHAR);
BEGIN
IF res = 0 THEN
IF ch = ech THEN Get ELSE res := 101 END
END
END Expect;

PROCEDURE SkipSpaces;
BEGIN
WHILE ch = ' ' DO Get END
END SkipSpaces;

PROCEDURE Comment (OUT c: ARRAY OF CHAR);
VAR i: INTEGER;
BEGIN
IF res # 0 THEN RETURN END;
i := 0;
WHILE ch # 0X DO
c[i] := ch; INC(i); Get
END;
c[i] := 0X
END Comment;

BEGIN
res := 0;
i := 0;
Get;
Real(x1);
Expect(',');
SkipSpaces;
Real(x2);
Expect(',');
SkipSpaces;
Real(x3);
SkipSpaces;
Expect(';');
SkipSpaces;
Comment(c)
END Parse;

А для более сложных случаев составляю грамматику EBNF и пользуюсь парсер-генератором.

yolki

Нее.. нафиг-нафиг. Copy в таком случае решает.
Кстати, про парсеры.
Каким генератором пользуешься?
А # - это от кого? fpc?

garikus

Вот этим
А # - это от кого? fpc?
Oberon

korsar0156

да, и поинтеры - это беее..
у джедаев не поинтеры.
я бы взял код джедаев

yolki

Джедайский код посмотрел - на порядки лучше.
Жаль, что в дельфях механизм функций с переменным числом параметров реализован через Ж и то, в одну сторону (см. тот же Format)

korsar0156

эм... а где он реализован правильно?
на мой взгляд наоборот в дельфе он наилучшим образом сделан.

Dasar

в шарпе, например.

korsar0156

а в шарпе как в Дельфе

Dasar

разве?
Приведи, пожалуйста, объявление и использование функции с переменным числом параметров на дельфи.

korsar0156

procedure AddStuff( Const A: Array of Const );
Var i: Integer;
Begin
For i:= Low(A) to High(A) Do
With A[i] Do
Case VType of
vtExtended: Begin
{ add real number, all real formats are converted to
extended automatically }
End;
vtInteger: Begin
{ add integer number, all integer formats are converted
to LongInt automatically }
End;
vtObject: Begin
If VObject Is DArray Then
With DArray( VObject ) Do Begin
{ add array of doubles }
End
Else If VObject Is IArray Then
With IArray( VObject ) Do Begin
{ add array of integers }
End;
End;
End; { Case }
End; { AddStuff }

Вызов вроде такого: AddStuff([3, 2.5, "2", obj]);
Динамические массивы конкретного типа тоже существуют в дельфе
arr: array of integer;

Dasar

> AddStuff([3, 2.5, "2", obj]);
Но вот это же один параметр, а не переменное число

korsar0156

а в чём принципиальная разница?
результат один и тот же.

Helga87

Разница в том, надо ли при вызове ставить скобочки или нет. Сомнительная радость писать
do([1, 2, 3]); 
вместо
do(1, 2, 3); 

yolki

Это примерно такой же довод, что "С лучше, потому что в нём {} короче, чем begin/end"
Радость есть.. Потому что работает именно так как надо. И есть возможность проконтролировать количество аргументов.

Helga87

ОК

Dasar

Массив кем и когда удаляется?

yolki

автомагически, по выходу из функции.
Да, про какой массив речь?

Dasar

который в квадратных скобках:

AddStuff([3, 2.5, "2", obj]);

Dasar

и тип массива он сам что ли выводит? как компилятор понимает, какой тип массива сделать?

yolki

да, копилятор понимает. Физически он делает "массив указателей" (потому что of const копирования объектов не происходит.
С точки зрения синтаксиса получается array of Variant.
этот массив существует, пока выполняется функция. после окончания выполнения - удаляется.
Оставить комментарий
Имя или ник:
Комментарий: