Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Joh
Lazarusforum e. V.
Beiträge: 176
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von Joh »

Nabend,

ich quäle mich gerade etwas mit sip herum.
da muß ich ja auf die Antwort der (in diesem Fall Fritzbox) achten.

ich bekomme hier von der Fritzbox allerdings einen Ansistring zurück, der Zeilenumbrüche enthält.

Code: Alles auswählen

SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.0.1;rport=60004;branch=z9hG4bKBB0407FF-1015-4203-AEE4-A6BF1DE5A5FD;received=192.168.0.33
From: 192.168.0.33 <sip:SIPbenutzer@192.168.0.1>;tag=195343125
To: 192.168.0.33 <sip:SIPbenutzer@192.168.0.1>;tag=EA0E7C2E860E398C
Call-ID: FB04FD3A-BD0F-4CA4-B18F-4AAB3CB6735C@192.168.0.1
CSeq: 1 REGISTER
WWW-Authenticate: Digest realm="fritz.box", nonce="BFC24FD94DD34902"
User-Agent: FRITZ!OS
Content-Length: 0
Aktuell benötige ich Zeile 7, ab 'realm='
pos() funktioniert nicht. Dabei habe ich nichtmal eine Ahnung, ob Nicht-Ascii-Zeichen verwendet werden dürften.

Was ist der sauberste Weg, den String zu zerlegen?
Erst In eine TStringList einlesen und dann zeilenweise durchgehen?

Ich glaube, ich muß erstmal etwas schlafen, dann hat sich das Problem hoffentlich von alleine erledigt...
just my two Beer

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

Re: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von theo »

Joh hat geschrieben:
So 5. Feb 2023, 01:06
pos() funktioniert nicht.
Wie kommst du da drauf?
Joh hat geschrieben:
So 5. Feb 2023, 01:06
Was ist der sauberste Weg, den String zu zerlegen?
Erst In eine TStringList einlesen und dann zeilenweise durchgehen?
Kommt drauf an, ob der gesuchte String (z.B. realm=") mehrfach vorkommen kann.
Falls nicht, kannst du gleich mit Pos arbeiten, ansonsten wäre vielleicht erstmal eine Stringlist nicht schlecht.
Erste Zeile löschen, dann mit Name/Value arbeiten und nach 'WWW-Authenticate' suchen.
Der NameValueSeparator sollte dabei ':' sein.
S.a. IndexOfName

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: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von Socke »

Joh hat geschrieben:
So 5. Feb 2023, 01:06
Dabei habe ich nichtmal eine Ahnung, ob Nicht-Ascii-Zeichen verwendet werden dürften.
Das steht doch im dazugehörigen RFC 3261?!
SIP is a text-based protocol and uses the UTF-8 charset (RFC 2279).
theo hat geschrieben:
So 5. Feb 2023, 08:42
Falls nicht, kannst du gleich mit Pos arbeiten, ansonsten wäre vielleicht eine Stringlist nicht schlecht.
Erste Zeile löschen, dann mit Name-Value arbeiten.
Mit einer TStringList kannst du das Aufteilen in einzelne Zeilen ganz einfach umsetzen und auch die Zeile bestimmen, in der ein Header anfängt. Da der Header dann aber weitere Zeilen umfassen kann, darfst du das Ende dann nochmal suchen.
https://www.rfc-editor.org/rfc/rfc3261#section-7.3..1 hat geschrieben:Header fields can be extended over multiple lines by preceding each
extra line with at least one SP or horizontal tab (HT). The line
break and the whitespace at the beginning of the next line are
treated as a single SP character.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
Roland Chastain
Beiträge: 156
Registriert: Sa 7. Jul 2012, 21:50
Wohnort: Saargemünd
Kontaktdaten:

Re: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von Roland Chastain »

Hallo

Wenn ich deine Frage richtig verstanden habe, ist hier eine Möglichkeit.

Code: Alles auswählen

uses
  SysUtils, RegExpr;

const
  SAMPLE =
  'SIP/2.0 401 Unauthorized' + LineEnding +
  'Via: SIP/2.0/UDP 192.168.0.1;rport=60004;branch=z9hG4bKBB0407FF-1015-4203-AEE4-A6BF1DE5A5FD;received=192.168.0.33' + LineEnding +
  'From: 192.168.0.33 <sip:SIPbenutzer@192.168.0.1>;tag=195343125' + LineEnding +
  'To: 192.168.0.33 <sip:SIPbenutzer@192.168.0.1>;tag=EA0E7C2E860E398C' + LineEnding +
  'Call-ID: FB04FD3A-BD0F-4CA4-B18F-4AAB3CB6735C@192.168.0.1' + LineEnding +
  'CSeq: 1 REGISTER' + LineEnding +
  'WWW-Authenticate: Digest realm="fritz.box", nonce="BFC24FD94DD34902"' + LineEnding +
  'User-Agent: FRITZ!OS' + LineEnding +
  'Content-Length: 0' + LineEnding;

begin
  with TRegExpr.Create('realm="([^"]+)"') do
  try
    if Exec(SAMPLE) then
      WriteLn(Match[1])
    else
      WriteLn('Not found');
  finally
    Free;
  end;
end.
Petit poisson deviendra grand,
Pourvu que Dieu lui prête vie.

Joh
Lazarusforum e. V.
Beiträge: 176
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

Re: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von Joh »

Danke euch...

i) Pos meldete mir immer 0 (aber s.u.)

ii) das RFC habe ich da, aber den Punkt nicht gelesen.
UTF8: ex geht nur um die interne Kommunikation mit der Fritzbox; da hoffe ich, davon ausgehen zu können, das nur Ascii-Zeichen verwendet werden.

iii) als prozedural-Programmierer widerstrebt es mir, ein (Rechenzeit-)teures Objekt temporär zu erzeugen ;-)

iv) Das mit dem Regex war auch eine Idee, aber das Regex ist für mich immer noch das 3-fach versiegelte Buch.
Aber wenn du es mir so auf den Tisch legst, werde ich es versuchen.

PS: ich war wohl nicht mehr Herr meiner Sinne. Es schien am Rechner noch alles ok zu sein, die Treppe bin ich hochgewankt, die Nacht nicht geschlafen und von Regex wachgeträumt und am nächsten morgen hatte ich 38,x° Fieber...
Danke, Corona.
just my two Beer

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: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von Winni »

Hi!

Pos meldet Null, weil der String bei CR LF zu Ende ist. Du liest also nur die erste Zeile.

Lies die Daten aus der Fritzbox in eine Stringlist ein.
Klapper alle Zeilen der Stringlist mit pos ab, bis Du einen Treffer erhälst.
Fertig.

Winni

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

Re: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von theo »

Winni hat geschrieben:
Mo 6. Feb 2023, 10:14
Pos meldet Null, weil der String bei CR LF zu Ende ist. Du liest also nur die erste Zeile.
Seit wann ist ein String bei CRLF "zu Ende"?
So ein Quatsch.

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: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von Winni »

theo hat geschrieben:
Mo 6. Feb 2023, 10:32
Winni hat geschrieben:
Mo 6. Feb 2023, 10:14
Pos meldet Null, weil der String bei CR LF zu Ende ist. Du liest also nur die erste Zeile.
Seit wann ist ein String bei CRLF "zu Ende"?
So ein Quatsch.
Hi!

Bei readln (MyString) ist der String bei CRLF zu Ende.
Anfängerwissen.

Winni

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

Re: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von theo »

Winni hat geschrieben:
Mo 6. Feb 2023, 10:45
Bei readln (MyString) ist der String bei CRLF zu Ende.
Anfängerwissen.
Und was hat das mit einem AnsiString zu tun?
Ich bekomme hier von der Fritzbox allerdings einen Ansistring zurück, der Zeilenumbrüche enthält.

Benutzeravatar
Roland Chastain
Beiträge: 156
Registriert: Sa 7. Jul 2012, 21:50
Wohnort: Saargemünd
Kontaktdaten:

Re: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von Roland Chastain »

Joh hat geschrieben:
Mo 6. Feb 2023, 09:45
Das mit dem Regex war auch eine Idee, aber das Regex ist für mich immer noch das 3-fach versiegelte Buch.
  • [^"] = Jedes Zeichen, das kein Anführungszeichen ist.
  • [^"]+ = Eine Folge von Zeichen, die keine Anführungszeichen sind.
  • ([^"]+) = Extrahieren die Folge von Zeichen, die keine Anführungszeichen sind.
:wink:
Petit poisson deviendra grand,
Pourvu que Dieu lui prête vie.

Benutzeravatar
KodeZwerg
Beiträge: 94
Registriert: Mo 6. Feb 2023, 11:04

Re: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von KodeZwerg »

Code: Alles auswählen

program Project1;
{$IFDEF MSWINDOWS}{$APPTYPE CONSOLE}{$ENDIF}

uses
  Classes;

const
  SAMPLE =
  'SIP/2.0 401 Unauthorized' + LineEnding +
  'Via: SIP/2.0/UDP 192.168.0.1;rport=60004;branch=z9hG4bKBB0407FF-1015-4203-AEE4-A6BF1DE5A5FD;received=192.168.0.33' + LineEnding +
  'From: 192.168.0.33 <sip:SIPbenutzer@192.168.0.1>;tag=195343125' + LineEnding +
  'To: 192.168.0.33 <sip:SIPbenutzer@192.168.0.1>;tag=EA0E7C2E860E398C' + LineEnding +
  'Call-ID: FB04FD3A-BD0F-4CA4-B18F-4AAB3CB6735C@192.168.0.1' + LineEnding +
  'CSeq: 1 REGISTER' + LineEnding +
  'WWW-Authenticate: Digest realm="fritz.box", nonce="BFC24FD94DD34902"' + LineEnding +
  'User-Agent: FRITZ!OS' + LineEnding +
  'Content-Length: 0' + LineEnding;

var
  sl: TStrings;
  i: Integer;
begin
  sl := TStringList.Create;
  try
    sl.Text := SAMPLE;
    for i := 0 to Pred(sl.Count) do
      if (Pos('realm', LowerCase(sl.Strings[i])) > 0) then
        WriteLn('Gefunden an SL-Index position ', i);
  finally
    sl.Free;
  end;
  {$IFDEF MSWINDOWS}ReadLn; {$ENDIF}
end.
Zuletzt geändert von KodeZwerg am Sa 39. Okt 6043, 29:87, insgesamt 43-mal geändert.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von wp_xyz »

Ohne RegEx:

Code: Alles auswählen

program Project1;

uses
  StrUtils;

const
  SAMPLE =
  'SIP/2.0 401 Unauthorized' + LineEnding +
  'Via: SIP/2.0/UDP 192.168.0.1;rport=60004;branch=z9hG4bKBB0407FF-1015-4203-AEE4-A6BF1DE5A5FD;received=192.168.0.33' + LineEnding +
  'From: 192.168.0.33 <sip:SIPbenutzer@192.168.0.1>;tag=195343125' + LineEnding +
  'To: 192.168.0.33 <sip:SIPbenutzer@192.168.0.1>;tag=EA0E7C2E860E398C' + LineEnding +
  'Call-ID: FB04FD3A-BD0F-4CA4-B18F-4AAB3CB6735C@192.168.0.1' + LineEnding +
  'CSeq: 1 REGISTER' + LineEnding +
  'WWW-Authenticate: Digest realm="fritz.box", nonce="BFC24FD94DD34902"' + LineEnding +
  'User-Agent: FRITZ!OS' + LineEnding +
  'Content-Length: 0' + LineEnding;
var
  p1, p2: Integer;
  searchStr: String;
begin
  searchStr := 'realm=';
  p1 := pos(searchStr, SAMPLE);
  if p1 = 0 then
    WriteLn('Kennung "', searchStr, '" nicht gefunden.')
  else
  begin
    p1 := p1 + Length(SearchStr);
    p2 := posEx(',', SAMPLE, p1);
    WriteLn('Gefunden: ', Copy(SAMPLE, p1, p2-p1));
  end;

  WriteLn;
  Write('Programm beenden mit RETURN...');
  ReadLn;
end. 

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: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von Winni »

theo hat geschrieben:
Mo 6. Feb 2023, 10:54
Und was hat das mit einem AnsiString zu tun?
Ich bekomme hier von der Fritzbox allerdings einen Ansistring zurück, der Zeilenumbrüche enthält.
Hi!

Das hat damit zu tun, dass ich vermute, dass er den String mit readln o.ä. einliest, und dann ist eben nach dem ersten CRLF Schluß - und sein pos gibt Null zurück.

Er sollte uns mal zeigen, wie er den String aus der FritzBox ausliest.

Winni

Benutzeravatar
KodeZwerg
Beiträge: 94
Registriert: Mo 6. Feb 2023, 11:04

Re: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von KodeZwerg »

Code: Alles auswählen

program Project1;
{$IFDEF MSWINDOWS}{$APPTYPE CONSOLE}{$ENDIF}

uses
  Classes;

const
  SAMPLE =
  'SIP/2.0 401 Unauthorized' + LineEnding +
  'Via: SIP/2.0/UDP 192.168.0.1;rport=60004;branch=z9hG4bKBB0407FF-1015-4203-AEE4-A6BF1DE5A5FD;received=192.168.0.33' + LineEnding +
  'From: 192.168.0.33 <sip:SIPbenutzer@192.168.0.1>;tag=195343125' + LineEnding +
  'To: 192.168.0.33 <sip:SIPbenutzer@192.168.0.1>;tag=EA0E7C2E860E398C' + LineEnding +
  'Call-ID: FB04FD3A-BD0F-4CA4-B18F-4AAB3CB6735C@192.168.0.1' + LineEnding +
  'CSeq: 1 REGISTER' + LineEnding +
  'WWW-Authenticate: Digest realm="fritz.box", nonce="BFC24FD94DD34902"' + LineEnding +
  'User-Agent: FRITZ!OS' + LineEnding +
  'Content-Length: 0' + LineEnding;


var
  sl: TStrings;
  Wort, s: string;
  i, ii: Integer;
begin
  Wort := 'realm';
  sl := TStringList.Create;
  try
    sl.Text := SAMPLE;
    for i := 0 to Pred(sl.Count) do
      if (Pos(Wort, LowerCase(sl.Strings[i])) > 0) then
        begin
          ii := Pos(Wort, LowerCase(sl.Strings[i]));
          s := Copy(sl[i], ii + Length(Wort), Succ(Length(sl[i]) - ii - Length(Wort)));
          WriteLn('Gefunden an SL-Index position ', i);
          WriteLn('Inhalt: ', s);
        end;
  finally
    sl.Free;
  end;
  {$IFDEF MSWINDOWS}ReadLn; {$ENDIF}
end.
Zuletzt geändert von KodeZwerg am Sa 39. Okt 6043, 29:87, insgesamt 43-mal geändert.

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

Re: Teilstring kopieren aus Ansistrings mit Zeilenumbrüchen

Beitrag von theo »

Gibt es eigentlich für sowas nicht eine fertige/allgemeine Funktion?

Ich habe mal kurz eine geschrieben:

Code: Alles auswählen

function CopyFromPosToPos(S: String; Start: String; Ende: String): String;
var
  A, B: integer;
begin
  Result := EmptyStr;
  if S=EmptyStr then exit;       
  A := Pos(Start, S);
  if A > 0 then
  begin
    Inc(A, Length(Start));
    if Ende = EmptyStr then
      B := Length(S)
    else
      B := Pos(Ende, S, A);
    if B > 0 then Result := Copy(S, A, B - A);
  end;
end;    
...
  CopyFromPosToPos(Memo1.Text, 'realm="', '"');
  CopyFromPosToPos(Memo1.Text, 'nonce="', '"');
Wenn man sicherstellen will, dass nur die Werte in der Zeile hinter 'WWW-Authenticate' in Frage kommen, könnte man es so machen.

Code: Alles auswählen

var SL:TStringList;
begin
  SL:=TStringList.Create;
  SL.NameValueSeparator:=':';
  SL.Text:=Memo1.Text; //Oder sonstwo her
  ShowMessage(CopyFromPosToPos(SL.Values['WWW-Authenticate'], 'realm="', '"'));     
  SL.Free;
end; 
Ach ja und gute Besserung!

EDIT: Habe die Funktion oben noch verbessert, so kann man auch andere Teile auslesen, die bis zum String-Ende gehen. z.B.

Code: Alles auswählen

CopyFromPosToPos(SL.Values['Via'], 'received=', '');      

Antworten