[Erledigt] Replace unbekannter string
-
- Lazarusforum e. V.
- Beiträge: 999
- Registriert: Do 17. Apr 2008, 01:59
- OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
- CPU-Target: Intel i7-10750 64Bit
- Wohnort: Freiburg
[Erledigt] Replace unbekannter string
Hallo,
ich überlege wie ich unbekannte Platzhalter ersetzen kann. Beispiel:
Martin kauft #Farbe# #Obstsorte#
Was zwischen den Rauten steht, ist nicht bekannt und soll samt Raute ersetzt werden!
Der neue Wert wird hierbei in einen Dialog eingesetzt und abgefragt.
Bitte gib eine Farbe ein:
Bitte gib eine Obstsorte ein:
Das Problem ist, möglichst elegant den String zu parsen.
Ich könnte in einer Schleife zeichenweise durch den String gehen, jedes Zeichen prüfen um dann entsprechend bei Auffinden einer Raute zu verzweigen. Dies erscheint mir jedoch reichlich ineffektiv.
Gibt es so etwas wie 'finde erstes Vorkommen eines Zeichens' und 'finde nächstes Vorkommen' oder 'finde alle Positionen eines Zeichens'?
ich überlege wie ich unbekannte Platzhalter ersetzen kann. Beispiel:
Martin kauft #Farbe# #Obstsorte#
Was zwischen den Rauten steht, ist nicht bekannt und soll samt Raute ersetzt werden!
Der neue Wert wird hierbei in einen Dialog eingesetzt und abgefragt.
Bitte gib eine Farbe ein:
Bitte gib eine Obstsorte ein:
Das Problem ist, möglichst elegant den String zu parsen.
Ich könnte in einer Schleife zeichenweise durch den String gehen, jedes Zeichen prüfen um dann entsprechend bei Auffinden einer Raute zu verzweigen. Dies erscheint mir jedoch reichlich ineffektiv.
Gibt es so etwas wie 'finde erstes Vorkommen eines Zeichens' und 'finde nächstes Vorkommen' oder 'finde alle Positionen eines Zeichens'?
Zuletzt geändert von MacWomble am Sa 9. Sep 2017, 11:02, insgesamt 1-mal geändert.
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
- af0815
- Lazarusforum e. V.
- Beiträge: 6200
- Registriert: So 7. Jan 2007, 10:20
- OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
- CPU-Target: 32Bit (64Bit)
- Wohnort: Burgenland
- Kontaktdaten:
Re: Replace unbekannter string
In den Lazarussourcen wird IMHO sowas ähnliches bei den Templates gemacht.
Andreas
Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
Re: Replace unbekannter string
MacWomble hat geschrieben:Ich könnte in einer Schleife zeichenweise durch den String gehen, jedes Zeichen prüfen um dann entsprechend bei Auffinden einer Raute zu verzweigen. Dies erscheint mir jedoch reichlich ineffektiv.
Warum? Irgend eint Tool muss das sowieso tun. Also warum nicht einfach selber durch den String gehen?
Ich würde es in diesem Fall so machen.
Wenn du es lieber kompliziert magst, kannst du auch Regular Expressions verwenden. http://wiki.freepascal.org/Regexpr/de
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2636
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Replace unbekannter string
MacWomble hat geschrieben:Gibt es so etwas wie 'finde erstes Vorkommen eines Zeichens' und 'finde nächstes Vorkommen' oder 'finde alle Positionen eines Zeichens'?
viewtopic.php?f=55&t=11004
Da wird beschrieben wie man Pos (bzw. PosEx) einen Parameter als Startpunkt mitgibt. Wenn du dafür den letzten Fundort verwendest kannst du nacheinander alle Doppelkreuze auffinden.
Bitte erst alle Positionen und ihre Inhalte einsammeln und anschließend ersetzen. Sonst verschiebt sich die Stringlänge und es geht schief.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
Re: Replace unbekannter string
Ich erkenne keinen Vorteil in der Verwendung von Pos gegenüber der einfachen, buchstabenweisen String Iteration.
Wir suchen ja Chars, keine Strings.
Wir suchen ja Chars, keine Strings.
-
- Lazarusforum e. V.
- Beiträge: 999
- Registriert: Do 17. Apr 2008, 01:59
- OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
- CPU-Target: Intel i7-10750 64Bit
- Wohnort: Freiburg
Re: Replace unbekannter string
Danke für die vielen Hinweise !
Ich werde das wohl tatsächlich Zeichenweise durchgehen, das scheint dann ja doch der sinnvolle Weg zu sein.
Die Regular Expressions scheinen hierfür nicht geeignet zu sein, da ich den zu ersetzenden Stringteil ja nicht kenne.
Ich werde das wohl tatsächlich Zeichenweise durchgehen, das scheint dann ja doch der sinnvolle Weg zu sein.
Die Regular Expressions scheinen hierfür nicht geeignet zu sein, da ich den zu ersetzenden Stringteil ja nicht kenne.
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
Re: [Erledigt] Replace unbekannter string
Falls das eine Aufgabe für Schule/Studium ist, solltest du das auf jeden Fall mit der Zeichen-Schleife lösen, auch falls du, andererseits, schon älter bist - das schmiert das Gehirn ungemein.
In den anderen Fällen sparst du dir ein paar Zeilen Code, wenn du den String-Helper Split aufrufst - den gibt es seit FPC 3 und er trennt den String an dem als Parameter übergebenen Zeichen auf und steckt die Teilstrings in ein Array. Du kannst dann dieses StringArray Element für Element durchlaufen und für jedes zweite Element den Eingabedialog aufrufen. Du musst nur aufpassen, ob der Eingabestring gleich mit einem Platzhalter beginnt.
In den anderen Fällen sparst du dir ein paar Zeilen Code, wenn du den String-Helper Split aufrufst - den gibt es seit FPC 3 und er trennt den String an dem als Parameter übergebenen Zeichen auf und steckt die Teilstrings in ein Array. Du kannst dann dieses StringArray Element für Element durchlaufen und für jedes zweite Element den Eingabedialog aufrufen. Du musst nur aufpassen, ob der Eingabestring gleich mit einem Platzhalter beginnt.
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2636
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Replace unbekannter string
theo hat geschrieben:Ich erkenne keinen Vorteil in der Verwendung von Pos gegenüber der einfachen, buchstabenweisen String Iteration.
Wir suchen ja Chars, keine Strings.
PosEx hat auch direkt eine Überladung die ein Char sucht. Klar kann man das problemlos auch alleine schreiben, denn die Implementierung von PosEx geht ja auch nur Zeichen für Zeichen durch (allerdings per IndexByte in Assembler geschrieben). Vorteil ist halt: ich schreibe keine neue Funktion dafür (die man ja auch wieder mit einer Testabdeckung versehen werden müsste), sondern benutze eine bekannte und bestehende. Ob es möglich ist vielleicht sogar schneller zu sein, in dem man eine eigene angepasste Funktion schreibt weiß ich nicht. Super-extreme Geschwindigkeit war aber auch nicht Anforderung.
MacWomble hat geschrieben:Die Regular Expressions scheinen hierfür nicht geeignet zu sein, da ich den zu ersetzenden Stringteil ja nicht kenne.
Genau dafür sind sie geeignet. Du kannst ja Platzhalter angeben.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
Re: Replace unbekannter string
m.fuchs hat geschrieben: Vorteil ist halt: ich schreibe keine neue Funktion dafür (die man ja auch wieder mit einer Testabdeckung versehen werden müsste), sondern benutze eine bekannte und bestehende.
Es geht natürlich beides, aber besonders lange testen muss ich für diese Zeile jetzt auch nicht...
Code: Alles auswählen
for i:=1 to length(s) do if s[i]='#' then..
.. und kann dann gleich weiter machen, mit dem Buffern des Schlüsselwortes.
P.S.: Der Trick mit Split (oder StringList.DelimitedText) ist natürlich auch nicht schlecht...
-
- Lazarusforum e. V.
- Beiträge: 999
- Registriert: Do 17. Apr 2008, 01:59
- OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
- CPU-Target: Intel i7-10750 64Bit
- Wohnort: Freiburg
Re: [Erledigt] Replace unbekannter string
Ich habe das nun doch mit RegExpr gelöst - Das kann ja recht viel (wenn man es mal kapiert hat).
Meine Lösung, falls jemand danach sucht:
Der Aufruf erfolgt z.B. so:
Meine Lösung, falls jemand danach sucht:
Code: Alles auswählen
function ReplacePlaceholder (AText : string;const ATag : char) : string;
var Ersatz: String;
begin
with TRegExpr.Create do try
Expression := '(' + ATag + '(.+?)' + ATag +')';
if Exec (AText) then
REPEAT
begin
if InputQuery('Abfragedialog', 'Bitte ' + copy(Match[1],2,length(Match[1])-2) + ' eingeben:', Ersatz) = True then
begin
AText:=StringReplace(AText,Match[1],Ersatz,[]);
Ersatz:='';
end;
end
UNTIL not ExecNext;
finally Free;
end;
Result:=Atext;
end;
Der Aufruf erfolgt z.B. so:
Code: Alles auswählen
Textneu:=ReplacePlaceholder(dbm_description.Text,'#');
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
-
- Beiträge: 369
- Registriert: Do 8. Jun 2017, 18:21
- OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
- CPU-Target: 64Bit
- Wohnort: Wien
Re: [Erledigt] Replace unbekannter string
Ich kann dir zu der Entscheidung nur gratulieren. Es ist mit großen Abstand der effizienteste Weg, etwas derartiges zu lösen. "Wenn du es lieber kompliziert magst," ist in Anbetracht des mit regex nötigen Codes im Vergleich zu jeder anderen Lösung schon ziemlicher Unfug.
Es wird übrigens noch eine Spur einfacher, wenn du die runden Klammern am Anfang und am Ende des Regex-Ausdrucks weglässt und im Abfragedialog statt einfach nur eingibst. Match[1] ist dann nämlich der Teil des gefundenen Matchs, der dem '(.+?)', ohne die Tags, entspricht. Der kompette Match-String steht dir automatisch in Match[0] zur Verfügung, d. h. den kompletten regex-Ausdruck in Klammern zu setzen ist immer überflüssig.
Es gibt eine überladene Version von create, der du die Expression direkt übergeben kannst.
Und Code zwischen brauchst du prinzipiell nicht in begin-end-Klammern setzen.
Wenn du sichergehen willst, dass ein beliebiges Sonderzeichen als Tag verwendet werden kann, dann solltest du statt nur der Variable Tag den String '\'+Tag verwenden. Denn es gibt ja in der Regex-Syntax eine Menge Sonderzeichen, die im String nicht für sich selbst stehen, sondern eine spezielle Bedeutung haben. Beim Tag # ist das nicht der Fall, aber wenn du als Begrenzer z.B. das Zeichen + verwenden würdest, dann würde das ganze so nicht funktionieren. Einem Sonderzeichen im Regex-String das Zeichen \ voranzustellen schadet nie und stellt sicher, dass das Zeichen vom Regex nicht "uminterpretiert" wird, auch wenn das nur bei manchen Sonderzeichen nötig ist.
Und NIE einen boolean-Ausdruck auf "=true" abfragen.
Mit diesen Änderungen schaut es dann so aus:
ACHTUNG: Anscheinend hat diese Forensoftwae einen Fehler: Im Code wird ein backslash nicht angezeigt, wenn er von einem ' gefolgt wird. Ich habe deshalb zwischen \ und ' jeweils eine Leerstelle eingefügt, aber die hat im richtigen Regex natürlich nichts verloren.
Es wird übrigens noch eine Spur einfacher, wenn du die runden Klammern am Anfang und am Ende des Regex-Ausdrucks weglässt und im Abfragedialog statt
Code: Alles auswählen
copy(Match[1],2,length(Match[1])-2)
Code: Alles auswählen
Match[1])
Es gibt eine überladene Version von create, der du die Expression direkt übergeben kannst.
Und Code zwischen
Code: Alles auswählen
repeat ... until
Wenn du sichergehen willst, dass ein beliebiges Sonderzeichen als Tag verwendet werden kann, dann solltest du statt nur der Variable Tag den String '\'+Tag verwenden. Denn es gibt ja in der Regex-Syntax eine Menge Sonderzeichen, die im String nicht für sich selbst stehen, sondern eine spezielle Bedeutung haben. Beim Tag # ist das nicht der Fall, aber wenn du als Begrenzer z.B. das Zeichen + verwenden würdest, dann würde das ganze so nicht funktionieren. Einem Sonderzeichen im Regex-String das Zeichen \ voranzustellen schadet nie und stellt sicher, dass das Zeichen vom Regex nicht "uminterpretiert" wird, auch wenn das nur bei manchen Sonderzeichen nötig ist.
Und NIE einen boolean-Ausdruck auf "=true" abfragen.
Mit diesen Änderungen schaut es dann so aus:
Code: Alles auswählen
function ReplacePlaceholder (const AText : string; const ATag : char) : string;
var Ersatz: String;
begin
Result:=Atext;
with TRegExpr.Create ('\ ' + ATag + '(.+?)\ ' + ATag) do try // leerstellen nach \ gehören gelöscht
if Exec (AText) then
REPEAT
ersatz:='';
if InputQuery('Abfragedialog', 'Bitte ' + Match[1] + ' eingeben:', Ersatz) then
Result:=StringReplace(Result,Match[0],Ersatz,[]);
UNTIL not ExecNext;
finally Free;
end;
end;
ACHTUNG: Anscheinend hat diese Forensoftwae einen Fehler: Im Code wird ein backslash nicht angezeigt, wenn er von einem ' gefolgt wird. Ich habe deshalb zwischen \ und ' jeweils eine Leerstelle eingefügt, aber die hat im richtigen Regex natürlich nichts verloren.
Zuletzt geändert von braunbär am So 10. Sep 2017, 13:29, insgesamt 1-mal geändert.
-
- Lazarusforum e. V.
- Beiträge: 999
- Registriert: Do 17. Apr 2008, 01:59
- OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
- CPU-Target: Intel i7-10750 64Bit
- Wohnort: Freiburg
Re: [Erledigt] Replace unbekannter string
@braunbär
Danke, das gefällt mir viel besser!
Bei ('\ ' + ATag + '(.+?)\ ' + ATag') do try ist das letzte ' zu viel!
Zum Abprüfen des boolschen Ausdrucks: Aufgrund der zuvor verwandten Programmiersprachen habe ich bisweilen solche Verwirrungen
Was RegEx angeht, werde ich mich künftig wohl mehr damit auseinandersetzen. Ist wirklich Klasse und - wenn man es mal kapiert hat - auch nicht kompliziert.
Danke, das gefällt mir viel besser!
Bei ('\ ' + ATag + '(.+?)\ ' + ATag') do try ist das letzte ' zu viel!
Zum Abprüfen des boolschen Ausdrucks: Aufgrund der zuvor verwandten Programmiersprachen habe ich bisweilen solche Verwirrungen
Was RegEx angeht, werde ich mich künftig wohl mehr damit auseinandersetzen. Ist wirklich Klasse und - wenn man es mal kapiert hat - auch nicht kompliziert.
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
Re: [Erledigt] Replace unbekannter string
MacWomble hat geschrieben:Was RegEx angeht, werde ich mich künftig wohl mehr damit auseinandersetzen. Ist wirklich Klasse und - wenn man es mal kapiert hat - auch nicht kompliziert.
Regex kann viel, deshalb hatte ich es auch als Option erwähnt.
Kompliziert trifft es vielleicht nicht ganz, aber kryptisch und nicht intuitiv leserlich ist es schon.
Beispiel:General Email Regex (RFC 5322 Official Standard)
Code: Alles auswählen
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
Man muss es halt mögen...
-
- Beiträge: 369
- Registriert: Do 8. Jun 2017, 18:21
- OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
- CPU-Target: 64Bit
- Wohnort: Wien
Re: [Erledigt] Replace unbekannter string
Naja, DAS muss man wahrscheinlich nicht mögen
In Pascal kann man ja Teilausdrücke als Konstante mit halbwegs sprechenden Namen definieren, und danach aus diesen Stringkonstanten den kompletten Regex-Ausdruck zusammenbauen - dann schaut auch der komplizierte Ausdruck schon wieder viel freundlicher aus.
Und was ist die Alternative? Ein spezialisierter Textparser, der eine Mailadresse auf valide Syntax checkt, wäre ja auch nicht unbedingt ganz trivial und in einer Minute zu durchschauen. Und wenn du das Programm gar unstrukturiert ohne vernünftige Formatierung in einer Wurst herunternudelst wie den Regex-Ausdruck, den du hier zeigst, dann verzweifelt jeder an dem Programm sicher ganz genau so wie an diesem Regex.
Ja, das stimmt, sorry. Habs in meinem Post ausgebessert.
In Pascal kann man ja Teilausdrücke als Konstante mit halbwegs sprechenden Namen definieren, und danach aus diesen Stringkonstanten den kompletten Regex-Ausdruck zusammenbauen - dann schaut auch der komplizierte Ausdruck schon wieder viel freundlicher aus.
Und was ist die Alternative? Ein spezialisierter Textparser, der eine Mailadresse auf valide Syntax checkt, wäre ja auch nicht unbedingt ganz trivial und in einer Minute zu durchschauen. Und wenn du das Programm gar unstrukturiert ohne vernünftige Formatierung in einer Wurst herunternudelst wie den Regex-Ausdruck, den du hier zeigst, dann verzweifelt jeder an dem Programm sicher ganz genau so wie an diesem Regex.
MacWomble hat geschrieben:Bei ('\ ' + ATag + '(.+?)\ ' + ATag') do try ist das letzte ' zu viel!
Ja, das stimmt, sorry. Habs in meinem Post ausgebessert.
-
- Lazarusforum e. V.
- Beiträge: 999
- Registriert: Do 17. Apr 2008, 01:59
- OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
- CPU-Target: Intel i7-10750 64Bit
- Wohnort: Freiburg
Re: [Erledigt] Replace unbekannter string
Die folgende Seite ist sehr hilfreich, wenn man mit RegEx arbeitet:
http://regexr.com/
und noch eine Seite mit zahlreichen vorgefertigten Ausdrücken:
https://www.freeformatter.com/regex-tester.html
http://regexr.com/
und noch eine Seite mit zahlreichen vorgefertigten Ausdrücken:
https://www.freeformatter.com/regex-tester.html
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.