![]() |
Strings aus Pascal-Datei filtern und exportieren
Ich begebe mich hier mit meinem Beispiel höchstwahrscheinlich auf dünnes Eis, was das korrekte Verwenden und Auswerten von Texten ist.
Ein paar Pascal-Dateien muss ich parsen und Stings rausfiltern und exportieren. Mein erster Versuch. [DELPHI] Ich begebe mich mal daran einen ganz schlechten Parser zu bauen, der Strings rausfiltert und stelle den dann hier vor. Könnte aber etwas dauern. Das scheitert bestimmt kläglich. Ob das mit RegEx einfacher ist, Strings rauszufiltern?
Delphi-Quellcode:
Ihr könnt zum Testen gerne diese Datei verwenden.
const
BaseFile: string = 'Language.EN.pas'; var i, j, LineIndexAllocation, LineIndexEndOfAssignment, PosStart, PosEnd: Integer; LLines, LLinesExport: TStringList; s, LUnitName, LFileToParse, LFileExport, LLine, LComponentOrVariable, LLineContentFilterted, msgcommentline, msgstrline, msgid, msgstr: string; BAllocationFound, BEndOfAssignmentFound: Boolean; Arr: TArray<string>; procedure AddDataToPOFile(Str: string); begin Str := Trim(Str); if IsHeader or (Pos('''', Str) > 0) then begin msgcommentline := '#. unit: ' + LUnitName + ', ' + LComponentOrVariable; msgstrline := '# ' + BaseFile + ':' + (LineIndexAllocation + 1).ToString; msgid := Str; msgstr := Str; LLinesExport.Add(msgcommentline); LLinesExport.Add(msgstrline); LLinesExport.Add('msgid "' + msgid + '"'); LLinesExport.Add('msgstr ""'); LLinesExport.Add(''); end; end; begin LLines := TStringList.Create; try LFileToParse := Path + BaseFile; if FileExists(LFileToParse) then begin LFileExport := 'Lang-export.po'; LLines.LoadFromFile(LFileToParse); if LLines.Count > 0 then begin LLinesExport := TStringList.Create; try LLinesExport.Add('msgid ""'); LLinesExport.Add('msgstr ""'); LLinesExport.Add('"POT-Creation-Date: \n"'); LLinesExport.Add('"PO-Revision-Date: \n"'); LLinesExport.Add('"Last-Translator: \n"'); LLinesExport.Add('"MIME-Version: 1.0\n"'); LLinesExport.Add('"Content-Type: text/plain; charset=iso-8859-1\n"'); LLinesExport.Add('"Content-Transfer-Encoding: 8bit\n"'); LLinesExport.Add('"Language: en\n"'); LLinesExport.Add('"X-Generator: NAME\n"'); LLinesExport.Add(''); LLinesExport.Add('# BASE FILE for translating NAME into other languages'); LLinesExport.Add('# Copyright (C) 1234 NAME'); LLinesExport.Add('# This file is distributed under the same license as NAME'); LLinesExport.Add('# NAME, 1234.'); LLinesExport.Add('# header end'); LLinesExport.Add(''); BAllocationFound := False; BEndOfAssignmentFound := False; LineIndexAllocation := -1; LineIndexEndOfAssignment := -1; for i := 0 to LLines.Count - 1 do begin LLine := LLines.Strings[i].Trim; if LLine = '' then Continue; if LLine.StartsWith('unit ') then begin LUnitName := Copy(LLine, Pos(' ', LLine), Length(LLine)); LUnitName := Trim(Copy(LUnitName, 1, Length(LUnitName) - 1)); Continue; end; // ('German', 'English') if LLine.Contains('(''') and LLine.Contains(',') and LLine.Contains(''')') then begin LComponentOrVariable := Trim(Copy(LLine, 1, Pos(':', LLine) - 1)); LLine := Copy(LLine, Pos('(', LLine) + 1, Length(LLine)); if LLine.EndsWith(');') then LLine := Copy(LLine, 1, Length(LLine) - 2); Arr := LLine.Split([',']); LineIndexAllocation := i; for s in Arr do AddDataToPOFile(s); Continue; end; if LLine.Contains(':=') then begin LComponentOrVariable := Trim(Copy(LLine, 1, Pos(':=', LLine) - 1)); BAllocationFound := True; LineIndexAllocation := i; end; if LLine.Contains(';') then begin BEndOfAssignmentFound := True; LineIndexEndOfAssignment := i; end; if BAllocationFound and BEndOfAssignmentFound then begin s := ''; for j := LineIndexAllocation to LineIndexEndOfAssignment do s := s + ' ' + LLines.Strings[j].Trim; PosStart := Pos(':=', s) + 2; PosEnd := Pos(';', s); AddDataToPOFile(Copy(s, PosStart, PosEnd - PosStart)); BAllocationFound := False; BEndOfAssignmentFound := False; end; end; if LLinesExport.Count > 0 then begin LLinesExport.SaveToFile(LFileExport); end; finally LLinesExport.Free; end; end; end; finally LLines.Free; end;
Delphi-Quellcode:
Wie kann man das optimieren, sodass es aber noch einfach bleibt und kein Langzeitprojekt wird?
unit Language.EN;
interface uses Winapi.Windows, System.SysUtils; type TDummyParent = record private const Languages: array [0 .. 2] of string = ('German', 'English'); public class var a, b, c, d: string; class procedure DummyProcedure; static; end; implementation class procedure TDummyParent.DummyProcedure; begin a := 'string-a'; b := 'string-b'; c := sLineBreak + 'string-d'; d := '1 2 3 ' + '4 5 6 ' + '7 8 9'; end; |
AW: Strings aus Pascal-Datei filtern und exportieren
Übersetzt werden müssen doch alle Texte.
Also auch die in 'ner MessageBox, ShowMessage ... und nicht nur die, die im Quelltext zugewiesen werden. Oder? Mein erster Ansatz wäre: Alle Dateien, die zu parsen sind ins Projekt aufnehmen, sie stehen dann in der .dpr. Die .dpr lesen und alle Zeilen zwischen uses und der ersten Leerzeile hinter uses lesen, dort stehen jeweils die Dateinamen hinter in zwischen Hochkommata. Das kann man dann als Dateinamen nehmen und an den Parser geben. Aus diesen Dateien werden alle Zeilen genommen, die mindestens ein Hochkomma enthalten. Für die Ausgabe dürfte das weitgehend reichen. Das Problem, das ich hier sehe ist eher: Wie kann man aus der übersetzten Datei denn dann die Texte wieder sinnvoll im Quelltext zuordnen. Vor allem dann, wenn der Quelltext im Rahmen einer Weiterentwicklung verändert wurde? Bin mir sicher, dass ich sowohl bei Deinem, als auch bei meinem Ansatz, hier kläglich scheitern würde. |
AW: Strings aus Pascal-Datei filtern und exportieren
Zitat:
Ich habe den Quelltext damals so gestaltet, dass ich alles den Komponenten entweder direkt zuweise oder, für MessageBoxes etc., in Variablen speichere. Zitat:
Zitat:
Zeilen ohne Hochkomma muss ich noch anders behandeln. Die sollen nicht exportiert werden. Aber es gibt auch Zuweisungen, die sich über mehrere Zeilen strecken. Zitat:
Die gefiltere Ausgabe der Testdatei oben
Code:
# Language.EN.pas:21
msgid "string-a" msgstr "" # Language.EN.pas:22 msgid "string-b" msgstr "" # Language.EN.pas:24 msgid "sLineBreak + 'string-d" msgstr "" # Language.EN.pas:26 msgid "1 2 3 ' + '4 5 6 ' + '7 8 9" msgstr "" |
AW: Strings aus Pascal-Datei filtern und exportieren
Wie wäre es mit etwas
![]()
Code:
bzw.
[a-z_]+ := '[^']*';
Code:
([a-z_]+)[ ]*:=[ ]*'([^']*)';
Ist jetzt ein einfaches Beispiel mit einfachen Strings, die keine ' enthalten und nur eine Zeile lang sind. ![]() ![]() wobei (man beachte die Match-Infos) ![]() ![]()
Code:
Und
(([a-z_]+)\s*:=\s*)?'([^']*)'
Code:
statt
[^']+
Code:
ignoriert alle Leerstrings
[^']*
Delphi-Quellcode:
.
''
|
AW: Strings aus Pascal-Datei filtern und exportieren
Ich habe RegEx außerhalb von PHP noch nie genutzt. Wie benutzt man das in Delphi?
Oben gehe ich die Datei zeilenweise durch und bekomme so natürlich auch dei Zeilennummer. Ich habe das jetzt ansonsten soweit optimiert, dass es für eine PO-Datei korrekt exportiert wird. Ich muss es nur noch auf eine ech8te Datei loslassen und keine Testdatei. Danach muss ich noch eine Procedur schreiben, die die PO-Datei ausließt und daraus eine verwertbare Dateü für mein Projekt liefert. Wenn ich fertig bin, zeige ich euch das Ergebnis. |
AW: Strings aus Pascal-Datei filtern und exportieren
![]() Dem kann man alles reingeben oder auch nacheinander einzelne Zeilen. Über die Optionen kann man auch sagen wie Zeilenumbrüche interpretiert werden, alles als "eine" Zeile oder nicht. (siehe Modifier/Options) Was dort an Ergebnisdaten in der Collection drin ist, das kannst dir im Debugger ansehn, oder siehe die Match-Infos im Regex-Tester. In der Collection steht zu jedem Ergebnis auch die Position, welche man sich selbst in die Zeile umrechnen kann, oder welches man sich von einem TMemo geben lassen kann. ![]() am Einfachsten die Zeilenumbrüche vor dem Zeichen zählen.
Delphi-Quellcode:
(etwas aktuelleres Delphi)
GefundenInZeile := DieDateiAlsString.substring(0, GefundenerCharIndex).CountChar(#10);
bzw.
Delphi-Quellcode:
Index := GefundenerCharIndex;
Zeile := -1; while Index >= 0 do begin Inc(Zeile); Dec(Index, Length(StringList[Zeile] + sLineBreak)); // bzw. der passende Zeilenumbruch end; GefundenInZeile := Zeile; |
AW: Strings aus Pascal-Datei filtern und exportieren
So richtig verstehe ich nicht, wie man das RegEx anwenden soll. Mein Beispiel von oben funktioniert. Hübsch ist was anderes. Aber wie oft brauche ich das? 1x im Jahr?
|
AW: Strings aus Pascal-Datei filtern und exportieren
Nja, in etwas aktuelleren Delphis ist ein TRegEx nun direkt dabei. (ansonsten gibt es dafür kostenlose Units)
Damit kann man den kompletten Suchcode auf 1-3 Zeilen Quellcode zusammenstampfen und braucht sich dann nur noch mit der Intepreation/Behandlung der gefundenen Dinge zu beschäftigen.
Delphi-Quellcode:
uses
System.RegularExpressions; procedure TForm11.FormCreate(Sender: TObject); var M: TMatch; begin S := 'abc d ef'#10'xyz'; for M in TRegEx.Matches(S, '[a-z]+') do // kannst dich auch mit M.NextMatch durchhangeln, statt dem FOR Memo1.Lines.Add(M.Index.ToString + ' ' + M.Value); // M.Groups wenn mit Klammern gearbeitet wurde und Teile davon benötigt werden if TRegEx.IsMatch(S, '^[a-z]+$', [roIgnoreCase]) then // in S gibt es nur Buchstaben, mindestens Einen |
AW: Strings aus Pascal-Datei filtern und exportieren
Bei mir passiert da nichts. Das Memo bleibt leer
Delphi-Quellcode:
LLines := TStringList.Create;
try LFileToParse := 'Language.EN.pas'; if FileExists(LFileToParse) then begin LLines.LoadFromFile(LFileToParse); if LLines.Count > 0 then begin for M in TRegEx.Matches(LLines.Text, '^[a-z]+$') do // kannst dich auch mit M.NextMatch durchhangeln, statt dem FOR Memo1.Lines.Add(M.Index.ToString + ' ' + M.Value); if TRegEx.IsMatch(LLines.Text, '^[a-z]+$', [roIgnoreCase]) then begin end; end; end; finally LLines.Free; end; |
AW: Strings aus Pascal-Datei filtern und exportieren
Jo, ich hatte beim Copy&Paste anfangs die ^ und $ im Pattern drin. (heimlich entfernt, bevor es wer merkt :angle2:)
Das findet dann natürlich nichts. Einfach nochmal das aktuelle Beispiel ansehn. Es sind auch nur BeispielPattern. Die Pattern zu deinem Problem siehe ganz oben. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:16 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz