2008-09-16 9 views
10

Quelqu'un at-il écrit une routine 'UnFormat' pour Delphi?Y at-il une fonction inverse de * SysUtils.Format * dans Delphi

Ce que je me fais est l'inverse de SysUtils.Format et ressemble à ceci

UnFormat ('un nombre% n et un autre% n' [flottant1, float2]);

Ainsi, vous pouvez décompresser une chaîne en une série de variables à l'aide de chaînes de format.

J'ai regardé la routine 'Format' dans SysUtils, mais je n'ai jamais utilisé l'assemblage, donc cela n'a aucun sens pour moi.

Répondre

12

Ceci est appelé scanf en C, je l'ai fait une Delphi Sosie semblable pour cela:

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

Merci pour cela. Juste ce que j'ai besoin. Exemple d'utilisation: ScanFormat ('numéro 27 Bonjour chaîne', 'numéro% d% s string', [@ anInt, @ aString]); Remarque: L'extraction d'une chaîne ne fonctionnera pas si le premier caractère qui suit la chaîne est également contenu dans la chaîne elle-même. –

1

J'ont tendance à prendre soin de cela en utilisant un analyseur simple. J'ai deux fonctions, on est appelé NumStringParts qui renvoie le nombre de « parties » dans une chaîne avec un séparateur spécifique (dans votre cas au-dessus de l'espace) et GetStrPart renvoie la partie spécifique d'une chaîne avec un séparateur spécifique. Ces deux routines ont été utilisées depuis mes jours Turbo Pascal dans de nombreux projets.

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; 

Exemple d'utilisation:

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; 

Ces routines pour faire des miracles par des virgules simples ou strictes chaînes délimitées aussi. Ces routines fonctionnent à merveille dans Delphi 2009/2010.

4

Je sais qu'il a tendance à effrayer les gens, mais vous pouvez écrire une fonction simple de le faire en utilisant des expressions régulières

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

Si vous êtes inquiet au sujet des expressions reg jetez un oeil à www.regexbuddy.com et vous ne verrez plus jamais arrière.

Questions connexes