2011-02-09 10 views
8

Próbuję wyodrębnić ciąg z pliku tekstowego, używając 2 ograniczników. Jeden na początek i jeden na zatrzymanie.Wyciągnij ciąg z pliku tekstowego za pomocą 2 ograniczników

Przykład:

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

Co muszę zrobić, aby wywołać funkcję, która wróci ciąg między $ i /. Szukałem wszędzie, ale nie mogę znaleźć czegoś użytecznego i jestem nowy w programowaniu.

Odpowiedz

11

Można to zrobić z Pos i 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

Użyj ['PosEx'] (http://docwiki.embarcadero.com/VCL/en/StrUtils.PosEx), aby wyszukać' Delim2' począwszy * po * lokalizacji 'Delim1'. –

+0

@Rob: Tak, to zwiększyłoby wydajność. –

+0

Dzięki dokładnie to, czego potrzebowałem !! – Gab

10

zrobiłbym to tak:

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

Dokładna ta sama sekunda. To fajnie. –

+0

@Andreas cool indeed –

4

Gab, można napisać funkcję, aby to zrobić przy użyciu klasy TFileStream i funkcje Copy i Pos.

zobaczyć tę próbkę:

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; 

i wykorzystywać w ten sposób

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

Zamiast SetLength + Read można również użyć TMemoryStream, następnie LoadFromFile(), a następnie SetString (Result, PAnsiChar (MemoryStream.Memory), MemoryStream.Size); –

2

Zakładając oba ograniczniki są pojedyncze znaki, jak na swój postu:

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; 

Zastosowanie:

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

w nowszej Delphi można zrobić to tak .. (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

Nie nadaje się najlepiej do wyrażeń regularnych, ale +1 do myślenia poza polem. – arthurprs

10

Powyższe funkcje nie będą działać, jeśli 2nd tekst jest również pojawiające się przed 1 wzór ...

PosEx() należy używać zamiast Pos():

można to zrobić z POS i Copy:

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

Pobierz wszystkie

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

Przyjemny pomysł na obsługę wielu wystąpień, ale nie jest to dobry projekt do stworzenia obiektu w ramach funkcji - kod wywołujący musi zarządzać zwalnianiem obiektu bez jego utworzenia.Lista łańcuchów powinna zostać utworzona (i zarządzana) przez kod wywołujący i przekazana przez odniesienie. – Argalatyr

+0

Jestem nowy w programowaniu. Po prostu dzielę się pomysłem. Być może ktoś to naprawi. – poetra

Powiązane problemy