Stringmanipulationen

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Benutzeravatar
Beach
Lazarusforum e. V.
Beiträge: 37
Registriert: Di 2. Nov 2021, 22:41
OS, Lazarus, FPC: Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hunsrück

Stringmanipulationen

Beitrag von Beach »

Ein gutes neues wünsche ich euch noch allen.
Bin seit langem mal wieder dabei etwas in Lazarus zu machen.
Habe vor etwa 3 Jahren ein kleines Programm für meine Arbeit geschrieben, welches eine Konfigurationsdatei einliest, ich dort möglichst einfach eine Seriennummer und 2 oder 3 andere Sachen umkonfigurieren kann.
Nun wurde die Steuerung auf einen neuen Stand gebracht und damit hat sich auch das Format der Config Datei leicht geändert und ich möchte mein Programm nun an die Änderungen anpassen, bzw das ganze etwas universeller machen.
Merke allerdings gerade das ich bei Lazarus ganz schön eingerostet bin, würde mich daher freuen wenn Ihr mir mit ein paar Tips auf die Sprüge helfen könnt.

ich habe, als Beispiel, folgende Zeile aus der Datei in einer Variable als String stehen:

Code: Alles auswählen

    CMM_Nr          = PRO-T  123456            ;% !Installation
Nun brauche ich einmal die sechsstellige Zahl um diese anzuzeigen, um diese dann anschließend mit einer anderen sechsstelligen Zahl in dem String zu ersetzen. Danach wird der String wieder in die Datei geschrieben.

Konkret meine Frage:
  • Wie lese ich die Zahl aus? Mir kommt da im ersten Moment RegEx in den Kopf? Aber das habe ich noch nie wirklich kapiert :( Oder gibt es was anderes brauchbares?
Das ersetzen sollte dann mit StringReplace wahrscheinlich kein Problem sein....

Vielen Dank für eure Hilfe

J.
MfG
Beach

Shit happens... Always in my shift

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Stringmanipulationen

Beitrag von theo »

Eine Zeile reicht nicht um das Muster zu erkennen.
Was ist denn da dazwischen als Trenner? Tab (#9)?

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringmanipulationen

Beitrag von Mathias »

Suche doch mal so die Position deines Parameters.

Code: Alles auswählen

var
  s: String:
  i: Integer;
  ...
i := Pos('PRO-T', s);
s.split kann auch helfen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Stringmanipulationen

Beitrag von Winni »

Hi!

Quick & dirty ohne Fehler-Check. Musst Du selbst ranschnitzen.

Code: Alles auswählen

procedure extract6digits (s: string; var pattern: string; var position: integer);
var i : integer;
    begin
    position := 0;
    pattern := '';
    for i := 1 to length(s) do
       begin
       if s[i] in ['0'..'9'] then
         begin
         if position = 0 then position := i;
         pattern := pattern +s[i];
         end;
       end;
    end;

Winni

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Stringmanipulationen

Beitrag von Socke »

Beach hat geschrieben:
Mi 4. Jan 2023, 17:24
Mir kommt da im ersten Moment RegEx in den Kopf?
Dann ist das ein Grund, in reguläre Ausrücke einzusteigen. Damit kann man viele Dinge recht einfach umsetzen.
Als Spielwiese empfehle ich https://regex101.com. Da kann man die Ausdrücke wunderbar testen. Die FreePascal Unit regexpr unterstützt zwar nicht alle Operationen und man muss auf das Greedy-Flag achten, aber vieles kann man übernehmen.

In deinem Fall wäre das:

Code: Alles auswählen

program Project1;

{$mode objfpc}{$H+}

uses
  Sysutils, Classes, regexpr;

const
  INPUT_STR = '    CMM_Nr          = PRO-T  123456            ;% !Installation';

var
  re: TRegExpr;
begin
  re:=TRegExpr.Create('(\d+)');
  try
    if re.Exec(INPUT_STR) then
    begin
      WriteLn('Regulluar Expression gefunden!');
      Write(INPUT_STR.Substring(0, re.MatchPos[0]-1)); // Text vor der Fundstelle
      Write('_REPLACED_');
      Write(INPUT_STR.Substring(re.MatchPos[0]+re.MatchLen[0], INPUT_STR.Length)); // Text nach der Fundstelle
      WriteLn(); // Zeilenumbruch am Ende einfügen
    end;
  finally
    re.Destroy;
  end;
  readln;
end.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
Beach
Lazarusforum e. V.
Beiträge: 37
Registriert: Di 2. Nov 2021, 22:41
OS, Lazarus, FPC: Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hunsrück

Re: Stringmanipulationen

Beitrag von Beach »

theo hat geschrieben:
Mi 4. Jan 2023, 17:35
Eine Zeile reicht nicht um das Muster zu erkennen.
Was ist denn da dazwischen als Trenner? Tab (#9)?
Sorry, aber mehr ist es halt nicht. Ich mu hier nur diese Zahl (Seriennummer der Anlage) ändern.
Davor sind 2 Leerzeichen und danach 10 Leerzeichen.
MfG
Beach

Shit happens... Always in my shift

Benutzeravatar
Beach
Lazarusforum e. V.
Beiträge: 37
Registriert: Di 2. Nov 2021, 22:41
OS, Lazarus, FPC: Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hunsrück

Re: Stringmanipulationen

Beitrag von Beach »

Oh. Da kamen noch 2 Antworten während ich am Tippen war.
Und gleich mit Beispiel Code.
Ihr seit die BEsten.

Werde mir das morgen auf der Arbeit genauer anschauen und möglichst direkt ausprobieren.
Ich gebe Bescheid was dabei raus gekommen ist.

Vielen Dank an alle soweit,
MfG
Beach

Shit happens... Always in my shift

kirchfritz
Beiträge: 169
Registriert: Mo 3. Jan 2011, 13:34
OS, Lazarus, FPC: Win10 (L 3.0 FPC 3.2.2)
CPU-Target: 64Bit
Wohnort: Nürnberg

Re: Stringmanipulationen

Beitrag von kirchfritz »

Ich behelfe mir seit Jahr und Tag mit zwei Hilfsfunktionen StrAfter (ermittelt die Zeichenkette nach einem Teilstring) und StrBefore (ermittelt die Zeichenkette vor einem Teilstring). Das erspart in den meisten Fällen den REGEX-"Dampfhammer".

Code: Alles auswählen

program Stringtest;

{$mode objfpc}{$H+}

uses
  Sysutils, Classes;

const
  INPUT_STR = '    CMM_Nr          = PRO-T  123456            ;% !Installation';

var
  OUTPUT_STR : String;

{******************************************************************************}
  function StrBefore(substr,source : String) : string;
  var p : integer;
  begin
    p := pos(substr,source);
    if p <= 1 then
      result := ''
    else
      result := copy(source,1,p-1);
  end;
{******************************************************************************}
  function StrAfter(substr,source : String) : string;
  var p : integer;
  begin
    p := pos(substr,source);
    if p < 1 then
      result := ''
    else
      result := copy(source,p+length(substr),length(source));
  end;
{******************************************************************************}

begin
  // Nimm aus dem INPUT_STR die Zeichenkette nach "PRO-T"
  // Nimm davon alles was vor ";" liegt
  // Entferne dann die Leerzeichen;
  OUTPUT_STR := trim(StrBefore(';',StrAfter('PRO-T',INPUT_STR)));
  writeln('>>',OUTPUT_STR,'<<');
  writeln('Press <ENTER> to continue...');
  Readln;
end.


Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Stringmanipulationen

Beitrag von Socke »

kirchfritz hat geschrieben:
Do 5. Jan 2023, 09:26
Das erspart in den meisten Fällen den REGEX-"Dampfhammer".
Regex ist in der Tat deutlich rechenintensiver. Wenn hier die Seriennummer immer an einer festen Position steht oder einfach als Ziffernfolge in Nichtziffern identifiziert werden kann, ist das auf jeden Fall effizienter.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Stringmanipulationen

Beitrag von theo »

Beach hat geschrieben:
Mi 4. Jan 2023, 20:21
theo hat geschrieben:
Mi 4. Jan 2023, 17:35
Eine Zeile reicht nicht um das Muster zu erkennen.
Was ist denn da dazwischen als Trenner? Tab (#9)?
Sorry, aber mehr ist es halt nicht. Ich mu hier nur diese Zahl (Seriennummer der Anlage) ändern.
Davor sind 2 Leerzeichen und danach 10 Leerzeichen.
Wenn alles rundherum immer gleich bleibt, dann reicht ja Copy und StringReplace
Dann verstehe ich aber deine Frage nicht.

Benutzeravatar
Beach
Lazarusforum e. V.
Beiträge: 37
Registriert: Di 2. Nov 2021, 22:41
OS, Lazarus, FPC: Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hunsrück

Re: Stringmanipulationen

Beitrag von Beach »

theo hat geschrieben:
Do 5. Jan 2023, 09:59
[...]
Wenn alles rundherum immer gleich bleibt, dann reicht ja Copy und StringReplace
Dann verstehe ich aber deine Frage nicht.
Danke.
Du hast vollkommen Recht. Ich habe viel zu kompliziert gedacht.
Mit Copy komme ich ganz einfach an die Zahlen.

:roll: :shock: :?
MfG
Beach

Shit happens... Always in my shift

Benutzeravatar
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: Stringmanipulationen

Beitrag von m.fuchs »

MODERATIONSHINWEIS: Die allgemeine Diskussion REGEX vs. Eigenbau habe ich mal verschoben.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: Stringmanipulationen

Beitrag von kupferstecher »

Die verschobene Regex-Diskussion ist mir Recht, ich hätte sonst gewartet, bis sich das Thema gelegt hat~

Über die Stringmanipulationen bin ich nämlich auch schon gestolpert und habe (vielleicht mangels Pascal-String-Wissen) mir letztlich eine eigene Bibliothek geschrieben, die sich an den String-Routinen von FORTRAN orientiert. Ich komm damit recht gut zurecht, es wäre aber interessant zu wissen, wie man das mit Pascal-Mitteln (besser) direkt macht.

Es gibt also INDEX, SCAN, VERIFY.

INDEX gibt die erste Position eines Suchstrings im String zurück.
SCAN gibt die erste Position eines beliebigen Zeichens des Suchstrings im String zurück.
VERIFY gibt die erste Position eines Zeichens im String zurück, das nicht im Suchstring enthalten ist.

Beispiele:

Code: Alles auswählen

pp: Integer;

pp:= INDEX('Hallo Welt','Welt'); //pp:= 7
pp:= SCAN('Hallo Welt','abc');   //pp:= 2
pp:= VERIFY('Hallo Welt','Hal'); //pp:= 5
Die Funktionen können dann optional auch noch Start- und Endpositionen haben:

Code: Alles auswählen

pp2:= SCAN(' Hallo Welt',' '+#9,2);      //pp2:= 7  //finde erstes Space oder Tab ab Zeichen 2
pp3:= VERIFY(' Hallo Welt',' '+#9, pp2); //pp3:= 8  //finde erstes Zeichen nach Space/Tab

if pp3 = 0 then writeln('Fehler: Zweites Wort erwartet aber nicht vorhanden');
Mit diesen Funktionen kann man sich dann schön linear durch den String durcharbeiten. Ich würde auch behaupten, dass das agorithmisch relativ schnell ist, weil auf Zwischenkopien verzichtet wird. Ein Problem sind aber Zeichenbereiche a-z, 0-9, die jeweils einzeln durchlaufen werden. Man bräuchte da vielleicht noch Spezialfunktionen.
Mit einer zusätzlichen Kopiefunktion AbsCopy kann man dann noch Substrings mit den Absolutpositionen rauskopieren:

Code: Alles auswählen

pp2:= SCAN('Hallo Welt ',' '+#9);        //pp2:= 6 //finde erstes Space oder Tab
pp3:= VERIFY('Hallo Welt ',' '+#9, pp2); //pp3:= 7 //finde erstes Zeichen nach Space/Tab
pp4:= RTrim('Hallo Welt '); //Erste Position von rechts, wo keine Leerzeichen sind
if pp3 <> 0 then ZweitesWort:= AbsCopy('Hallo Welt', pp3, pp4); //ZweitesWort:= 'Welt'
Also wie würde so etwas mit vorgegebenen Pascal-Routinen aussehen (auch in Hinblick auf komplizierteres Parsen, wo ein einfaches split nicht reicht)?

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Stringmanipulationen

Beitrag von theo »

kupferstecher hat geschrieben:
Do 5. Jan 2023, 23:21
Also wie würde so etwas mit vorgegebenen Pascal-Routinen aussehen?
Vieles findet man in StrUtils, insb. PosEx, PosSet etc.

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: Stringmanipulationen

Beitrag von kupferstecher »

theo hat geschrieben:
Fr 6. Jan 2023, 00:39
PosEx, PosSet etc.
Danke, das ist genau das. Dann fehlt nur noch ein Äquivalent zu VERIFY, wahrscheinlich gibts das auch in irgend einer Form.

Vielleicht könnte man in gemeinsamer Forumsanstrengung einen Wikiartikel über Stringparsing machen, ich denke das ist ein wichtiges Thema.

Antworten