2008-09-16 8 views
10

Hat jemand eine 'UnFormat'-Routine für Delphi geschrieben?Gibt es eine umgekehrte Funktion von * SysUtils.Format * in Delphi

Was ich Vorstellen bin, ist die inverse von SysUtils.Format und sieht so etwas wie dieses

UnFormat ('eine Zahl% n und eine andere% n', [float1, float2]);

So könnten Sie eine Zeichenkette in eine Reihe von Variablen mit Formatzeichenfolgen entpacken.

Ich habe die 'Format' Routine in SysUtils angesehen, aber ich habe nie Assembly verwendet, so dass es für mich bedeutungslos ist.

Antwort

12

Diese scanf in C genannt wird, habe ich für diese eine Delphi-Look-a-like gemacht:

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

Danke dafür. Nur was ich brauche. Beispielverwendung: ScanFormat ('Nummer 27 Zeichenfolge Hallo', 'Nummer% d Zeichenfolge% s', [@ anInt, @ aString]); Hinweis: Das Extrahieren einer Zeichenfolge funktioniert nicht, wenn das erste Zeichen, das auf die Zeichenfolge folgt, auch in der Zeichenfolge selbst enthalten ist. –

1

Ich neige dazu, dies zu kümmern einen einfachen Parser verwenden. Ich habe zwei Funktionen, eine heißt NumStringParts, die die Anzahl der "Teile" in einer Zeichenfolge mit einem bestimmten Trennzeichen (in Ihrem Fall über dem Leerzeichen) zurückgibt und GetStrPart gibt den bestimmten Teil aus einer Zeichenfolge mit einem bestimmten Trennzeichen zurück. Beide Routinen wurden seit meinen Turbo Pascal Tagen in vielen Projekten eingesetzt.

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; 

Anwendungsbeispiel:

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; 

Diese Routinen arbeiten Wunder für einfache oder streng durch Komma getrennt zu Strings. Diese Routinen funktionieren wunderbar in Delphi 2009/2010.

4

Ich weiß, es neigt dazu, Menschen zu erschrecken, aber man konnte eine einfache Funktion schreibt dies mit regulären Ausdrücken

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

zu tun Wenn Sie sich Sorgen um reg Ausdrücke einen Blick auf www.regexbuddy.com nehmen und Sie werden nie sehen zurück.

Verwandte Themen