2008-09-16 22 views
10

Czy ktoś napisał procedurę "UnFormat" dla Delphi?Czy istnieje odwrotna funkcja * SysUtils.Format * w Delphi

Co ja sobie wyobrażam jest odwrotny z SysUtils.Format i wyglądać tak

UnFormat ('numer% N i inną% N', [float1, float2]);

Można więc rozpakować łańcuch na serię zmiennych za pomocą ciągów formatów.

Przyjrzałem się procedurze "Formatowania" w SysUtils, ale nigdy nie używałem zestawu, więc nie ma dla mnie znaczenia.

Odpowiedz

12

To się nazywa scanf w C, zrobiłem Delphi look-a-jak na to:

function ScanFormat(const Input, Format: string; Args: array of Pointer): Integer; 
var 
    InputOffset: Integer; 
    FormatOffset: Integer; 
    InputChar: Char; 
    FormatChar: Char; 

    function _GetInputChar: Char; 
    begin 
    if InputOffset <= Length(Input) then 
    begin 
     Result := Input[InputOffset]; 
     Inc(InputOffset); 
    end 
    else 
     Result := #0; 
    end; 

    function _PeekFormatChar: Char; 
    begin 
    if FormatOffset <= Length(Format) then 
     Result := Format[FormatOffset] 
    else 
     Result := #0; 
    end; 

    function _GetFormatChar: Char; 
    begin 
    Result := _PeekFormatChar; 
    if Result <> #0 then 
     Inc(FormatOffset); 
    end; 

    function _ScanInputString(const Arg: Pointer = nil): string; 
    var 
    EndChar: Char; 
    begin 
    Result := ''; 
    EndChar := _PeekFormatChar; 
    InputChar := _GetInputChar; 
    while (InputChar > ' ') 
     and (InputChar <> EndChar) do 
    begin 
     Result := Result + InputChar; 
     InputChar := _GetInputChar; 
    end; 

    if InputChar <> #0 then 
     Dec(InputOffset); 

    if Assigned(Arg) then 
     PString(Arg)^ := Result; 
    end; 

    function _ScanInputInteger(const Arg: Pointer): Boolean; 
    var 
    Value: string; 
    begin 
    Value := _ScanInputString; 
    Result := TryStrToInt(Value, {out} PInteger(Arg)^); 
    end; 

    procedure _Raise; 
    begin 
    raise EConvertError.CreateFmt('Unknown ScanFormat character : "%s"!', [FormatChar]); 
    end; 

begin 
    Result := 0; 
    InputOffset := 1; 
    FormatOffset := 1; 
    FormatChar := _GetFormatChar; 
    while FormatChar <> #0 do 
    begin 
    if FormatChar <> '%' then 
    begin 
     InputChar := _GetInputChar; 
     if (InputChar = #0) 
     or (FormatChar <> InputChar) then 
     Exit; 
    end 
    else 
    begin 
     FormatChar := _GetFormatChar; 
     case FormatChar of 
     '%': 
      if _GetInputChar <> '%' then 
      Exit; 
     's': 
      begin 
      _ScanInputString(Args[Result]); 
      Inc(Result); 
      end; 
     'd', 'u': 
      begin 
      if not _ScanInputInteger(Args[Result]) then 
       Exit; 

      Inc(Result); 
      end; 
     else 
     _Raise; 
     end; 
    end; 

    FormatChar := _GetFormatChar; 
    end; 
end; 
+0

Dzięki za to. Właśnie to czego potrzebuje. Przykład użycia: ScanFormat ("numer 27 ciąg Hello", "numer% d ciąg% s", [@ anInt, @ aString]); Uwaga: Wyodrębnianie ciągu znaków nie będzie działać, jeśli pierwszy znak występujący po ciągu znaków jest również zawarty w samym ciągu. –

1

staram się dbać o to za pomocą prostego parsera. Mam dwie funkcje, jedna nazywa się NumStringParts, która zwraca liczbę "części" w ciągu znaków ze specjalnym ogranicznikiem (w twoim przypadku powyżej spacji), a GetStrPart zwraca określoną część z łańcucha z określonym ogranicznikiem. Obie te procedury były używane od czasów mojego Turbo Pascala w wielu projektach.

function NumStringParts(SourceStr,Delimiter:String):Integer; 
var 
    offset : integer; 
    curnum : integer; 
begin 
    curnum := 1; 
    offset := 1; 
    while (offset <> 0) do 
    begin 
     Offset := Pos(Delimiter,SourceStr); 
     if Offset <> 0 then 
     begin 
      Inc(CurNum); 
      Delete(SourceStr,1,(Offset-1)+Length(Delimiter)); 
     end; 
    end; 
    result := CurNum; 
end; 

function GetStringPart(SourceStr,Delimiter:String;Num:Integer):string; 
var 
    offset : integer; 
    CurNum : integer; 
    CurPart : String; 
begin 
    CurNum := 1; 
    Offset := 1; 
    While (CurNum <= Num) and (Offset <> 0) do 
    begin 
     Offset := Pos(Delimiter,SourceStr); 
     if Offset <> 0 then 
     begin 
      CurPart := Copy(SourceStr,1,Offset-1); 
      Delete(SourceStr,1,(Offset-1)+Length(Delimiter)); 
      Inc(CurNum) 
     end 
     else 
     CurPart := SourceStr; 
    end; 
    if CurNum >= Num then 
    Result := CurPart 
    else 
    Result := ''; 
end; 

Przykład zastosowania:

var 
    st : string; 
    f1,f2 : double; 
    begin 
    st := 'a number 12.35 and another 13.415'; 
    ShowMessage('Total String parts = '+IntToStr(NumStringParts(st,#32))); 
    f1 := StrToFloatDef(GetStringPart(st,#32,3),0.0); 
    f2 := StrToFloatDef(GetStringPart(st,#32,6),0.0); 
    ShowMessage('Float 1 = '+FloatToStr(F1)+' and Float 2 = '+FloatToStr(F2)); 
    end; 

Procedury te cuda dla prostych lub ściśle oddzielonych przecinkami łańcuchów też. Te procedury działają cudownie w Delphi 2009/2010.

4

Wiem, że to wydaje się przestraszyć ludzi, ale można napisać prostą funkcję, aby to zrobić za pomocą wyrażeń regularnych

'a number (.*?) and another (.*?) 

Jeśli martwi wyrażenia reg przyjrzeć www.regexbuddy.com i nigdy nie będziesz wyglądać plecy.

Powiązane problemy