Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   StringReplace-Funktion etwas aufbohren (https://www.delphipraxis.net/211076-stringreplace-funktion-etwas-aufbohren.html)

DieDolly 24. Jul 2022 19:01

StringReplace-Funktion etwas aufbohren
 
Ich übergebe der einen String (Textdatei) und eine Zeichenkette zum ersetzen.
Aus 123 soll dann ABC werden, grob gesagt.

Ich möchte aber gerne, dass nur jene 123 ersetzt werden, die nicht zwischen < und > stehen. "hallo 123 du" soll zu "hallo abc du" werden, aber "hier könnte <irgendetwas stehen 123. mir fällt gerade> nix ein" soll nicht zu "hier könnte <irgendetwas stehen abc. mir fällt gerade> nix ein" werden.

Wie wäre soetwas möglich? Das < und > muss nicht zwangsweise direkt vor oder hinter 123 stehen.

Für Hilfe wäre ich sehr dankbar.

himitsu 24. Jul 2022 19:12

AW: StringReplace-Funktion etwas aufbohren
 
ganz billig:
* mehrmals ersetzen
* <OldPattern> durch einen Platzhalter
* dann OldPattern durch NewPattern
* und am Ende den Platzhalter zurück zu <OldPattern>

in deinem StringReplace:
* zwei mal suchen (PosEx) nach "<123>" und "123"
* nur wenn der aktuelle Treffer nicht von Beiden gefunden wurde, dann ersetzen, ansonsten weitersuchen

* oder nach OldPattern suchen
* dann prüfen, ob < bzw. > davor/dahinter und nur ersetzen, wenn nicht


Oder ganz banal mit RegEx, was Diesbezüglich bereits alles bietet.
Delphi-Referenz durchsuchenTRegEx

DieDolly 24. Jul 2022 19:40

AW: StringReplace-Funktion etwas aufbohren
 
Es ist ja nicht <123> was ich suche. Vor und hinter dem 123 zum < und > kann noch viel anderer Kram stehen. Sonst wäre es ja einfach.

Zitat:

* oder nach OldPattern suchen
* dann prüfen, ob < bzw. > davor/dahinter und nur ersetzen, wenn nicht
Das hatte ich vor weiß aber nicht wie.

Ganz grob erklärt sollen Vorkommen nicht ersetzt werden, wenn die sich innerhalb von html tag klammern befinden. Das kann aber auch mal ein img mit base64-kodierung sein.
Und da habe ich keine Ahnung wie man sowas auch nur annähernd performant umsetzen könnte.

KodeZwerg 24. Jul 2022 20:47

AW: StringReplace-Funktion etwas aufbohren
 
Interessante Thematik.

Meine Theorie:

1. Original String-Kopie per Pos() nach "<" suchen lassen
2. Original String-Kopie von 1 bis #1 in einen neuen kopieren
3. diese neue kopie per StringReplace bearbeiten
4. per Pos() nach ">" suchen
5. diesen mini-string an #3 anheften
6. Original String-Kopie von 1 bis #4 löschen
7. wiederhole ab #1

DieDolly 24. Jul 2022 21:20

AW: StringReplace-Funktion etwas aufbohren
 
Das klingt funktionabel. Es handelt sich hierbei um eine HTML-Datei.
Es können in so einer Datei gerne mehrere base64-img-tags auftauchen und dazu noch normale html-tags.
Ich habe schon überlegt in den Dateien gewisse Abschnitte mit eigenen html-tags zu markieren (ignore-begin, ignore-end) und sowas aber das wäre im Prinzip dasselbe wie mit < und >.

KodeZwerg 24. Jul 2022 21:26

AW: StringReplace-Funktion etwas aufbohren
 
eine html datei kann man doch als xml reinladen und dann in den nodes stringreplace anwenden oder täusche ich mich? (ich mach zu selten etwas mit delphi und html, sorry)

himitsu 24. Jul 2022 21:43

AW: StringReplace-Funktion etwas aufbohren
 
Nein, nur Strict-HTML wäre kompatibel zu XML.

Aber es gibt auch HTML-Komponenten für Delphi.




nochmal: lass das rumgepfusche

* entweder eine HTML-Komponente, welche genau für sowas gedacht ist
* oder RegEx, was durch komplexere Regeln mehr kann
Delphi-Referenz durchsuchenTRegEx.Replace

Echt mal, warum will sich jeder die Arbeit schwerer machen, als es sein muß?
Oder fummelst du durm Ändern eines Pixels in einem TFileStream rum, anstatt im TBitmap.Canvas?

Uwe Raabe 24. Jul 2022 22:07

AW: StringReplace-Funktion etwas aufbohren
 
Zitat:

Zitat von himitsu (Beitrag 1509174)
* oder RegEx, was durch komplexere Regeln mehr kann

Nee jetzt: Using regular expressions to parse HTML: why not?

DieDolly 24. Jul 2022 22:38

AW: StringReplace-Funktion etwas aufbohren
 
Ich lade die HTML-Datei in den HtmlViewer. XML bringt mir am Ende leider nichts.

himitsu 25. Jul 2022 07:25

AW: StringReplace-Funktion etwas aufbohren
 
Ja, darum zuerst HTML-Komponente. :zwinker:

Ansonsten bietet RegEx.Replace das, was jemand im StringReplace suchen wollte.

DieDolly 25. Jul 2022 10:41

AW: StringReplace-Funktion etwas aufbohren
 
Kannst du mir da auf die Sprünge helfen?
Wenn ich mir Punkte für RegEx geben müsste, hätte ich 0 von 10.

Bei Regex101.com: abcd <img ganzvielblödsinnabcdefghistehthier > efghi

Delphi.Narium 25. Jul 2022 11:02

AW: StringReplace-Funktion etwas aufbohren
 
Anderer Vorschlag:

HTML in 'ne MemoryStream laden und zeichenweise in einen zweiten MemoryStream schreiben.
Vor jedem < einen Zeilenumbruch schreiben.
Hinter jedem > einen Zeilenumbruch schreiben.
Alle übrigen Zeilenumbrüche durch ein Leerzeichen ersetzen.

Zweiten MemoryStream in 'ne Stringliste laden.

Diese Stringliste enthält nun nur noch Zeilen, die entweder ein HTML-Tag enthalten oder nur aus reinem Text bestehen.

StringReplace nur in den Zeilen aus reinem Text ausführen.

DieDolly 25. Jul 2022 11:29

AW: StringReplace-Funktion etwas aufbohren
 
Wie füge ich denn beides wieder zusammen? Ich brauche am Ende alles zusammen quasi im Originalzustand.

himitsu 25. Jul 2022 11:30

AW: StringReplace-Funktion etwas aufbohren
 
Leerzeichen und Zeilenumbrüche stellen im HTML keine Veränderung dar.

DieDolly 25. Jul 2022 11:33

AW: StringReplace-Funktion etwas aufbohren
 
Dann verstehe ich den Ansatz oben nicht und was mir diese zweite StringList bringen soll.

Zitat:

StringReplace nur in den Zeilen aus reinem Text ausführen.
Das geht alleine schon wegen den base64-enkodierten Bildern nicht.

Weil wenn ich das StringReplace auf die StringList ausführe bringt mir das nichts. Ich muss das StringReplace direkt auf den HTML-Content des HtmlViewers ausführen.

KodeZwerg 25. Jul 2022 11:38

AW: StringReplace-Funktion etwas aufbohren
 
aber im HTML ist doch ein bild per
Delphi-Quellcode:
<img src="data:image/png;base64,...../>
in einem TAG und wird somit nicht berührt?!

DieDolly 25. Jul 2022 11:44

AW: StringReplace-Funktion etwas aufbohren
 
Ich denke das klappt alles nicht. Das zeichenweise Durchgehen könnte sehr lange dauern, weil diese Prozedur auch 3x oder 4x die Sekunde aufgerufen werden kann.

KodeZwerg 25. Jul 2022 11:50

AW: StringReplace-Funktion etwas aufbohren
 
Vielleicht so: (da hier jede menge Informationen zwecks Ablauf fehlen)
Einen Hashwert der HTML erzeugen und mit vorhandenem Hash abgleichen, wenn ungleich eine neue in-memory Datei wie von Delphi.Narium beschrieben erzeugen und anwenden, wenn gleich dann mache nichts.

DieDolly 25. Jul 2022 11:56

AW: StringReplace-Funktion etwas aufbohren
 
Ich durchsuche das Htmlviewer-Element (den HTML-Datei) live beim Eintippen in ein Eingabefeld.
Die Eingabe wird, wenn gefunden, markiert. Werden nun aber Vorkommen markiet die sich innerhalb eines HTML-Tags befinden, wird das Dokument zerstört.

himitsu 25. Jul 2022 12:21

AW: StringReplace-Funktion etwas aufbohren
 
Ja, es wird zwar von RegEx bei HTML abgeraten, aber das liegt vorwiegend an der Verschachtelung von HTML-Tags und daß diese auch noch "defekt" sein dürfen können.
IMG hat aber keine untergeordnete TAGs und selbst bei Strict-HTML kann man das eventuelle schließende </img> ignorieren.

Problematisch würde es nur, wenn zwischen <img und src= noch weitere Attribute vorkämen, aber wenn man das ausschließen kann, dann stört sowas ja nicht. :angle2:

DieDolly 25. Jul 2022 12:22

AW: StringReplace-Funktion etwas aufbohren
 
Verschachtelte HTML-Tags kann ich nicht ausschließen.

himitsu 25. Jul 2022 12:25

AW: StringReplace-Funktion etwas aufbohren
 
Ja, aber doch nicht innerhalb eines
Delphi-Quellcode:
<img ....>


Problem bei RegEx ist, dass man z.B. zu einem <td> nicht das schließende </td> "sicher" finden kann, bei einer unbekanten Anzahl an weiteren Tags innerhalb.
Abgesehn davon, dass das Schließende sogar fehlen könnte.


Aber genau dafür gibt es für HTML passende Komponenten, genauso, wie man für XML auch eine XML-Komponente und kein StringReplace verwendet.

DieDolly 25. Jul 2022 12:27

AW: StringReplace-Funktion etwas aufbohren
 
Nein das nicht.

DBR 25. Jul 2022 15:53

AW: StringReplace-Funktion etwas aufbohren
 
Ich habe mir vor längerer Zeit mal einen Code gebastelt, der eingeklammerte Begriffe übergeht, und bei dem man zusätzlich bestimmen kann, wieviel Ersetzungen vorgenommen werden können. Nach längerem Suchen habe ich das Ding gefunden. Man braucht nur normale Klammern gegen spitze austauschen! Vielleicht hilft es. Wenn nicht, dann eben nicht.
Gruß DBR

function XReplace(const s, OldPattern, NewPattern: string; Number: integer;
IgnoreCase: Boolean; Auf: String = '('; Zu: String = ')'): string;
var
pc, ps, ph, x, z, lga, lgn, lgs: integer;
c, v: string;
begin
lga := length(OldPattern);
if (lga > 0) then
begin
lgn := length(NewPattern);
z := 0;
v := lowercase(OldPattern);
lgs := length(s);
try
x := 1;
while x <= lgs do
begin
c := copy(s, x, lga);
pc := pos(Auf, c);
ps := pos(Zu, copy(s, x + pc, maxint));
if (ps > 0) and (pc > 0) then
begin
ph := pos(Auf, copy(s, x + pc, maxint));
if (ph = 0) or (ph > ps) then
begin
Result := Result + copy(c, 1, pc);
inc(x, pc);
c := copy(s, x, ps);
Result := Result + c;
inc(x, ps);
continue;
end;
end;
if (c = OldPattern) or (IgnoreCase and (lowercase(c) = v)) then
begin
if lgn > 0 then
begin
Result := Result + NewPattern;
end;
inc(z);
inc(x, lga);
if z = Number then
break;
end
else
begin
Result := Result + copy(c, 1, 1);
inc(x);
end;
end;
Result := Result + copy(s, x, lgs - pred(x));
except
Result := 'FEHLER';
end;
end
else
Result := s;
end;

// Beispiel 1: ergibt 'Versuch1<Versuch2< Test3 >Versuch4<Test5> Versuch'
// da Test3 und Test 5 ordnungsgemäß in spitzen Klammern stehen
procedure TForm1.Button1Click(Sender: TObject);
var
Wieoft: integer;
Ignorcase: Boolean;
begin
Wieoft := -1; // Alle Vorkommen
Ignorcase := True; // bei False würde nichts ersetzt
ListBox1.items.add(XReplace('Test1<Test2< Test3 >Test4<Test5> Test', 'test',
'Versuch', Wieoft, Ignorcase, '<', '>'));
end;

// Beispiel 2: ergibt 'Versuch1<Versuch2< Test3 >Versuch4<Test5> Test'
// da das letzte "Test" bereits der vierte zu ändernde Begriff wäre
procedure TForm1.Button2Click(Sender: TObject);
var
Wieoft: integer;
Ignorcase: Boolean;
begin
Wieoft := 3; // nur die ersten drei, die nicht in spitzen Klammern stehen
Ignorcase := True;
ListBox1.items.add(XReplace('Test1<Test2< Test3 >Test4<Test5> Test', 'test',
'Versuch', Wieoft, Ignorcase, '<', '>'));
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:55 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 by Thomas Breitkreuz