2016-11-15 8 views
-1

После просмотра Delphi extract string between to 2 tags и пробовав код, указанный Андреасом Реджбрандом, я понял, что мне нужна версия, которая не остановится после одного тега - моя цель - написать все значения, которые происходят между двумя строками в нескольких XML-файлах в файле журнала.Запись всех экземпляров строк между двумя другими строками в файл журнала

<screen> xyz </screen> blah blah <screen> abc </screen> 

-> давая логфайл с
хуг
аЬс
... и так далее.

Что я пытался было удалить часть текста, прочитанную функцией, так что, когда функция повторяется, она перейдет к следующему экземпляру нужной строки, а затем напишет это в файл журнала, пока не будет match left - логическая функция будет true, и функция может остановиться - ниже слегка измененной функции, основанной на версии в ссылке.

function ExtractText(const Tag, Text: string): string; 
var 
    StartPos1, StartPos2, EndPos: integer; 
    i: Integer; 
    mytext : string; 
    bFinished : bool; 

begin 
    bFinished := false; 
    mytext := text; 
    result := ''; 
    while not bFinished do 
    begin 
    StartPos1 := Pos('<' + Tag, mytext); 
    if StartPos1 = 0 then bFinished := true; 
    EndPos := Pos('</' + Tag + '>', mytext); 
    StartPos2 := 0; 
    for i := StartPos1 + length(Tag) + 1 to EndPos do 
     if mytext[i] = '>' then 
     begin 
     StartPos2 := i + 1; 
     break; 
     end; 

    if (StartPos2 > 0) and (EndPos > StartPos2) then 
    begin 
     result := result + Copy(mytext, StartPos2, EndPos - StartPos2); 
     delete (mytext, StartPos1, 1); 
    end 

Поэтому я создаю форму и назначаю файл журнала.

procedure TTagtextextract0r.FormCreate(Sender: TObject); 
begin 
    Edit2.Text:=(TDirectory.GetCurrentDirectory); 
    AssignFile(LogFile, 'Wordlist.txt'); 
    ReWrite(LogFile); 
    CloseFile(Logfile); 
end; 

Чтобы получить файлы, о которых идет речь, я нажимаю кнопку, которая затем читает их.

procedure TTagtextextract0r.Button3Click(Sender: TObject); 
begin 
    try 
    sD := TDirectory.GetCurrentDirectory; 
    Files:= TDirectory.GetFiles(sD, '*.xml'); 
    except 
    exit 
    end; 

    j:=Length(Files); 
    for k := 0 to j-1 do 
    begin 
    Listbox2.Items.Add(Files[k]); 
    sA:= TFile.ReadAllText(Files[k]); 
    iL:= Length(sA); 

    AssignFile(LogFile, 'Wordlist.txt'); 
    Append(LogFile); 
    WriteLn(LogFile, (ExtractText('screen', sA))); 
    CloseFile (LogFile); 
    end; 
end; 

end. 

Моя проблема заключается в том, что без булева цикла в функции, то приложение пишет только одну строки на файл, а затем останавливается, но с булевым кодом приложение застревает в бесконечном цикле - но я не могу достаточно увидеть, где цикл не заканчивается. Возможно ли, что команда «WriteLn» не может затем вывести результат функции? Если он не может, я не знаю, как получить новую строку для каждого запуска функции - что я делаю неправильно здесь?

+1

Учиться 1) правильно отложить свой код, чтобы вы могли видеть, где начинаются и останавливаются блоки, и 2) научитесь использовать отладчик, чтобы пройти через код, чтобы увидеть, что происходит. В этом случае установите точку останова в 'ListBox2.Items.Add (Файлы [k]);' и выполните код с помощью F8 для выполнения каждой строки. (И подсказка: переместите 'AssignFile' до начала цикла и' CloseFile' до конца цикла. Нет смысла открывать и закрывать его повторно в каждой итерации цикла.) –

+0

Обратите внимание, что вы можете использовать ' PosEx' для продолжения поиска с последней позиции, поэтому избегайте использования 'delete'. – MBo

+2

Использование анализатора xml –

ответ

1

Прежде всего, необходимо, чтобы получить контроль над отладкой

Посмотрите на this post на брифинг о том, как сделать паузу и отладки программы Нервничавшей.

Также читайте Setting and modifying breakpoints, чтобы узнать, как использовать контрольные точки. Если бы вы перешли через свой код, вы бы скоро увидели, где вы ошибетесь.

Тогда к вашей проблеме:

В старых версиях Delphi (до Delphi XE2), вы можете использовать функцию PosEx() (как это было предложено в комментариях), что позволит упростить код в ExtractText() функции значительно. От Delphi XE3 функция System.Pos() была расширена с той же функциональностью, как PosEx(), то есть третий параметр Offset: integer

Так как вы на Delphi 10 Сиэтле можно использовать взаимозаменяемо либо System.StrUtils.PosEx() или System.Pos().

System.StrUtils.PosEx

PosEx() возвращает индекс SubStr в S, начиная поиск в Offset

function PosEx(const SubStr, S: string; Offset: Integer = 1): Integer; inline; overload; 

Реализация ExtractText() может выглядеть следующим образом (с PosEx()):

function ExtractText(const tag, text: string): string; 
var 
    startPos, endPos: integer; 
begin 
    result := ''; 
    startPos := 1; 

    repeat 
    startPos := PosEx('<'+tag, text, startpos); 
    if startPos = 0 then exit; 
    startPos := PosEx('>', text, startPos)+1; 
    if startPos = 1 then exit; 

    endPos := PosEx('</'+tag+'>', text, startPos); 
    if endPos = 0 then exit; 

    result := result + Copy(text, startPos, endPos - startPos) + sLineBreak; 
    until false; 
end; 

Я добавил sLineBreak (в блоке System.Types) после каждого найденного текста, иначе он должен работать так, как вы предполагали (я считаю).

+0

В новых версиях Delphi (Unicode), [System.Pos()] (http://docwiki.embarcadero.com/Libraries/en/System.Pos) эквивалентно 'System.StrUtils.PosEx()'. –

+1

@LURD святой ...! Ну, это похоже. Спасибо, я этого не знал. Мне нужно перефразировать мой пост. –

+0

@LURD У меня есть пробел в моих установках. D2010 Pos() не распознает третий параметр. DXE4 делает. У вас есть какие-либо из XE, XE2 или XE3, установленные для проверки, когда произошло изменение? –

 Смежные вопросы

  • Нет связанных вопросов^_^