2008-09-16 6 views
10

¿Alguien ha escrito una rutina 'UnFormat' para Delphi?¿Hay una función inversa de * SysUtils.Format * en Delphi

Lo que yo estoy imaginando es la inversa de SysUtils.Format y se ve algo como esto

UnFormat ('un número n% n% y otro', [float1, float2]);

Para poder descomprimir una cadena en una serie de variables usando cadenas de formato.

He visto la rutina 'Formato' en SysUtils, pero nunca he utilizado el ensamblado, por lo que no tiene sentido para mí.

Respuesta

12

Esto se llama scanf en C, he hecho un vistazo Delphi-a-igual que para esto:

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

Gracias por esto. Justo lo que necesito. Ejemplo de uso: ScanFormat ('number 27 string Hello', 'number% d string% s', [@ anInt, @ aString]); Nota: La extracción de una cadena no funcionará si el primer carácter que sigue a la cadena también está contenido en la cadena misma. –

1

que tienden a hacerse cargo de esto usando un analizador simple. Tengo dos funciones, una se llama NumStringParts que devuelve el número de "partes" en una cadena con un delimitador específico (en su caso sobre el espacio) y GetStrPart devuelve la parte específica de una cadena con un delimitador específico. Ambas rutinas se han utilizado desde mis días de Turbo Pascal en muchos proyectos.

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; 

Ejemplo de uso:

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; 

Estas rutinas hacer maravillas para cadenas simples o estrictos delimitados por comas demasiado. Estas rutinas funcionan maravillosamente en Delphi 2009/2010.

4

sé que tiende a asustar a la gente, pero se podría escribir una función simple de hacer esto usando expresiones regulares

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

Si usted está preocupado acerca de las expresiones reg echar un vistazo a www.regexbuddy.com y usted nunca mirará espalda.

Cuestiones relacionadas