2011-02-09 18 views
8

Estoy tratando de extraer una cadena de un archivo de texto usando 2 delimitadores. Uno para comenzar y otro para detenerse.Extraer cadena de un archivo de texto utilizando 2 delimitadores

Ejemplo:

Hi my name is$John and I'm happy/today 

Lo que tiene que hacer es llamar a una función que devuelve la cadena entre $ y /. He estado buscando en todas partes pero parece que no puedo encontrar algo útil y soy nuevo en la programación.

Respuesta

11

Usted puede hacerlo con Pos y Copy:

function ExtractText(const Str: string; const Delim1, Delim2: char): string; 
var 
    pos1, pos2: integer; 
begin 
    result := ''; 
    pos1 := Pos(Delim1, Str); 
    pos2 := Pos(Delim2, Str); 
    if (pos1 > 0) and (pos2 > pos1) then 
    result := Copy(Str, pos1 + 1, pos2 - pos1 - 1); 
end; 
+16

Utilice ['PosEx'] (http://docwiki.embarcadero.com/VCL/en/StrUtils.PosEx) para buscar' Delim2' starting * after * la ubicación de 'Delim1'. –

+0

@Rob: Sí, eso aumentaría el rendimiento. –

+0

¡Gracias exactamente lo que necesitaba! – Gab

10

lo haría algo como esto:

function ExtractDelimitedString(const s: string): string; 
var 
    p1, p2: Integer; 
begin 
    p1 := Pos('$', s); 
    p2 := Pos('/', s); 
    if (p1<>0) and (p2<>0) and (p2>p1) then begin 
    Result := Copy(s, p1+1, p2-p1-1); 
    end else begin 
    Result := '';//delimiters not found, or in the wrong order; raise error perhaps 
    end; 
end; 
+0

Exacto el mismo segundo. Eso es muy bonito. –

+0

@Andreas cool de hecho –

4

Gab, puede escribir una función para hacer esto utilizando una clase TFileStream y las funciones Copy y Pos.

ver esta muestra:

uses 
    Classes, 
    SysUtils; 

function ExtractString(Const FileName: TFileName;Const IDel,FDel : AnsiString) : AnsiString; 
Var 
FileStream : TFileStream; 
i,f  : Integer; 
begin 
    FileStream:= TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); //oopen the file 
    try 
    try 
     SetLength(Result, FileStream.Size); //set the size of the string 
     FileStream.Read(Pointer(Result)^, FileStream.Size);//read the content into a string 
     i:=Pos(IDel,Result);//search the initial delimiter 
     f:=Pos(FDel,Result);//search the final delimiter 
     Result:=Copy(Result,i+1,f-i-1); //extract the value between the delimiters 
    except 
     Result := ''; 
     raise; 
    end; 
    finally 
    FileStream.Free; 
    end; 
end; 

y utilizan de esta manera

ExtractString('your_file_name','$','/'); 
+0

En lugar de SetLength + Read, también puede usar un TMemoryStream, luego LoadFromFile() y luego SetString (Resultado, PAnsiChar (MemoryStream.Memory), MemoryStream.Size); –

2

Suponiendo ambos delimitadores son caracteres individuales como por su mensaje:

function ExtractDelimitedValueFromFile(const aFilename: String; 
             const aOpenDelim: Char; 
             const aCloseDelim: Char; 
             var aValue: String): Boolean; 
var 
    i: Integer; 
    strm: TStringStream; 
    delimStart: Integer; 
    delimEnd: Integer; 
begin 
    result  := FALSE; 
    aValue  := ''; 
    delimStart := -1; 
    delimEnd := -1; 

    strm := TStringStream.Create; 
    try 
    strm.LoadFromFile(aFileName); 

    for i := 1 to strm.Size do 
    begin 
     if (delimStart = -1) and (strm.DataString[i] = aOpenDelim) then 
     delimStart := i 
     else if (delimStart <> -1) and (strm.DataString[i] = aCloseDelim) then 
     delimEnd := i; 

     result := (delimStart <> -1) and (delimEnd <> -1); 
     if result then 
     begin 
     aValue := Copy(strm.DataString, delimStart + 1, delimEnd - delimStart - 1); 
     BREAK; 
     end; 
    end; 

    finally 
    strm.Free; 
    end; 
end; 

Uso:

var 
    str: String; 
    begin 
    if ExtractDelimitedValueFromFile('path\filename.ext', '$', '/', str) then 
     // work with str 
    else 
     // delimited value not found in file 
    end; 
3

En el más reciente de Delphi puede hacerlo de esta manera .. (yay)

program Project40; {$APPTYPE CONSOLE} 

uses RegularExpressions; 

const 
    str = 'Is$John and I''m happy/today'; 

function GetStr(const aStr: string): string; 
begin 
    Result := TRegEx.Match(aStr, '\$.*/').Value; 
    Result := Copy(Result, 2, Length(Result) - 2); 
end; 

begin 
    Writeln(GetStr(str)); 
    ReadLn; 
end. 
+0

No es el mejor uso para las expresiones regulares, pero +1 para pensar fuera de la caja. – arthurprs

10

Las funciones anteriores no funcionarán si el segundo texto también está apareciendo antes de la primera patrón ...

debe utilizar PosEx() en lugar de Pos():

puede hacerlo con Pos y copiar:

function ExtractText(const Str: string; const Delim1, Delim2: string): string; 
var 
    pos1, pos2: integer; 
begin 
    result := ''; 
    pos1 := Pos(Delim1, Str); 
    if pos1 > 0 then begin 
    pos2 := PosEx(Delim2, Str, pos1+1); 
    if pos2 > 0 then 
     result := Copy(Str, pos1 + 1, pos2 - pos1 - 1); 
    end; 
end; 
7

Obtener todos

function ExtractText(const Str: string; const Delim1, Delim2: string): TStringList; 
var 
    c,pos1, pos2: integer; 
begin 
    result:=TStringList.Create; 
    c:=1; 
    pos1:=1; 

    while pos1>0 do 
    begin 
    pos1 := PosEx(Delim1, Str,c); 
    if pos1 > 0 then begin 
     pos2 := PosEx(Delim2, Str, pos1+1); 
    if pos2 > 0 then 
     result.Add(Copy(Str, pos1 + length(delim1), pos2 - (length(delim1) + pos1))); 
     c:=pos1+1; 
    end; 

    end; 
end; 
+0

Buena idea para manejar múltiples ocurrencias, pero no es un buen diseño para crear el objeto dentro de la función; el código de llamada debe administrar liberando el objeto sin haberlo creado.La lista de cadenas debe ser creada (y gestionada) por el código de llamada y pasada por referencia. – Argalatyr

+0

Soy nuevo en programación. Solo compartiendo idea. Tal vez, alguien puede arreglarlo. – poetra

Cuestiones relacionadas