AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein RegEx: fehlerhafter Zeilenumbruch (PostgreSQL)
Thema durchsuchen
Ansicht
Themen-Optionen

RegEx: fehlerhafter Zeilenumbruch (PostgreSQL)

Ein Thema von himitsu · begonnen am 12. Jul 2016 · letzter Beitrag vom 14. Jul 2016
Antwort Antwort
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#1

RegEx: fehlerhafter Zeilenumbruch (PostgreSQL)

  Alt 12. Jul 2016, 11:20
Moin,

bis gestern funktionierte ein RegEx und dann urplötzlich nicht mehr und ich weiß nicht warum und keine hat (angeblich) an den Settings gespielt.
Nur ein Kollege am Sprach-/Datumsformat des Servers, um was zu Testen, aber auch ein Zurücksetzen half natürlich nichts.
Und das Neustarten des Server/DBServer brachte auch nichts.

Was ich endlich rausfand ist, daß Zeilenumbrüche und \s sich im Verhalten verändert haben.
Modifier sind nur "mi" (MultiLine und CaseInsensitive)

SQL-Code:
CREATE OR REPLACE FUNCTION INI_GetValue(ini TEXT, section VARCHAR, name VARCHAR, defvalue VARCHAR DEFAULT '') RETURNS VARCHAR AS $$
  -- SELECT+regexp_matches liefert "keinen" Datensatz, wenn nichts gefunden wurde, daher das SUBSELECT mit COALESCE
  SELECT nullif(coalesce((SELECT (regexp_matches(ini, '^\\[' || section || '\\]\\s*$[^\\[]*^' || name || '=(.*)$', 'mi'))[1]), defvalue), '')
$$ LANGUAGE SQL IMMUTABLE;
Also, das erste ^ findet noch einen Zeilenumbruch, \s trifft plözlich auch Zeilenumgrüche, obwohl z.B. der Modifier "s" (SingleLine) nicht angegeben ist.
und weitere ^ oder $ treffen keinen Zeilenumbruche im Text mehr.

Die Doppelten \\ sind korrect, da es ja einmal das Escape von Postgres und dann nochmal vom RegEx ist.
Allerdings ging es bis gestern noch, daß ich in Postgres die \ nicht brauchte, wenn es keinen "Steuerbefehl" ergab, also z.B. kein Buchstabe folgte, womit auch '\[xxx\]' den Abschnitt traf und heute nur noch '\\[xxx\\]' funktioniert.

Code:
[zzz]
bbb=nee
[xxx]
aaa=nee
bbb=ok
ccc=nee
mit "^\[xxx\]\s*$[^\[]*^bbb=(.*)$" und "mi" sollte "ok" im ersten Match liefern.
https://regex101.com/r/uQ4aP9/1



Mein aktueller "Lösungsansatz" gefällt mir so garnicht, voralem da man im RegEx danach garnicht mehr erkennt, was der macht.
  • an den Text vorne und hinten ein '\n' anhängen
  • \s durch [ \t] ersetzen
  • .* durch [^\r\n]*
  • mühevoll die Zeilenumbrüche ^ und $ mit \r?\n([^\r\n]*\r?\n)
  • usw.



Ich hatte einfach nur versucht vorhandene "Funktionen" endlich mal in Funktionen zu packen
und als ich fertig war und es testen wollte, da ging es anfangs und dann mittendrin plötzlich nicht mehr.
SQL-Code:
--value = INI_GetValue(ini, section, name, [defvalue])
--ini = INI_SetValue(ini, section, name, value)
--value = SL_GetValue(list, name, [defvalue])
--list = SL_SetValue(list, name, value)

CREATE OR REPLACE FUNCTION INI_GetValue(ini TEXT, section VARCHAR, name VARCHAR, defvalue VARCHAR DEFAULT '') RETURNS VARCHAR AS $$
  -- SELECT+regexp_matches liefert "keinen" Datensatz, wenn nichts gefunden wurde, daher das SUBSELECT mit COALESCE
  SELECT nullif(coalesce((SELECT (regexp_matches(ini, '^\\[' || section || '\\]\\s*$[^\\[]*^' || name || '=(.*)$', 'mi'))[1]), defvalue), '')
$$ LANGUAGE SQL IMMUTABLE;

CREATE OR REPLACE FUNCTION INI_SetValue(ini TEXT, section VARCHAR, name VARCHAR, value VARCHAR) RETURNS TEXT AS $$
DECLARE seA TEXT;
        seN TEXT;
BEGIN
  -- altes weg ... der Lookbehind will nicht, wie er soll, als erst Section extrahieren und dann darin den Value entferen
  --ini := regexp_replace(ini, '(?<!^\\[' || section || '\\]\\s*$[^\\[]*)^' || name || '=(.*)$', '', 'mi');
  seA := (regexp_matches(ini, '^\\[' || section || '\\]\\s*$[^\\[]*^' || name || '=(.*)$', 'mi'))[0];
  seN := regexp_replace(seA, '^' || name || '=(.*)$', '', 'mi');
  ini := replace(ini, seA, seN);
  -- neues rein
  IF regexp_matches(ini, '^\\[' || section || '\\]\\s*$', 'mi') IS NULL THEN
    ini := concat(ini, '\r\n[', section, ']');
  END IF;
  IF (value <> '') and (value IS DISTINCT FROM defvalue) THEN
    ini := regexp_replace(ini, '^\\[' || section || '\\]\\s*$', concat('[', section, ']\r\n', name, '=', value), 'mi');
  END IF;
  -- fertig
  return ini;
END $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION SL_GetValue(list TEXT, name VARCHAR, defvalue VARCHAR DEFAULT '') RETURNS VARCHAR AS $$
  -- SELECT+regexp_matches liefert "keinen" Datensatz, wenn nichts gefunden wurde, daher das SUBSELECT mit COALESCE
  SELECT nullif((SELECT (regexp_matches(list, '^' || name || '=(.*)$', 'mi'))[1]), '')
$$ LANGUAGE SQL IMMUTABLE;

CREATE OR REPLACE FUNCTION SL_SetValue(list TEXT, name VARCHAR, value VARCHAR) RETURNS TEXT AS $$
BEGIN
  -- altes weg
  list := regexp_replace(list, '=(.*)$', '', 'mi');
  -- neues rein
  IF (value <> '') and (value IS DISTINCT FROM defvalue) THEN
    list := concat(list, '\r\n', name, '=', value);
  END IF;
  -- sortieren
  return trim(array_to_string(ARRAY(SELECT regexp_split_to_table(list, '\r?\n' , 'mi') ORDER BY 1), '\r\n')' \r\n');
END $$ LANGUAGE plpgsql;

-- Test = [zzz]\nbbb=nee\n[xxx]\naaa=nee\nbbb=ok\nccc=nee
-- Test2 = aaa=nee\nbbb=ok\nccc=nee

SELECT INI_GetValue(GetSetting('Test'), 'xxx', 'bbb')
SELECT SL_GetValue(GetSetting('Test2'), 'bbb')
Ein paar kleine "Bugs" gibt es zusätzlich noch, denn $[^\[]*^ ist falsch, da es nicht "Alles außer [" sondern "Alles außer wenn [ am Zeilenanfang" heißen müsste,
aber k.A. wie das gehn soll, da Lookarounds keine .* drin haben wollen.
$2B or not $2B

Geändert von himitsu (12. Jul 2016 um 11:52 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: RegEx: fehlerhafter Zeilenumbruch (PostgreSQL)

  Alt 14. Jul 2016, 17:18
Hab zwar immernoch keine Ahnung, was das Problem ist , aber zumindestens hab ich erstmal wider eine funktionierende Version.

SQL-Code:
-- INI-TEXT und StringList-TEXT (Name=Value) in der DB behandeln

  -- line = SL_GetLine (list, index)
  -- value = SL_GetValue(list, name, [defvalue])
  -- list = SL_SetValue(list, name, value, [defvalue])
  -- value = INI_GetValue(ini, section, name, [defvalue])
  -- ini = INI_SetValue(ini, section, name, value, [defvalue])

  -- Initial : SELECT SetSetting('Test', 'aaa=nee\r\nbbb=ok\r\nccc=nee'), SetSetting('Test2', '[zzz]\r\nbbb=nee\r\n[xxx]\r\naaa=nee\r\nbbb=ok\r\nccc=nee')
  -- SL-Test : SELECT GetTextSetting('Test'), SL_GetValue(GetSetting('Test'), 'bbb'), SL_SetValue(GetSetting('Test'), 'bbb', 'NEU'), SL_SetValue(GetSetting('Test'), 'bbc', 'NEU')
  -- SL-Test2 : SELECT GetTextSetting('Test'), SL_GetLine(GetSetting('Test'), 1), SL_GetLine(GetSetting('Test'), 3), SL_GetLine(GetSetting('Test'), 4)
  -- INI-Test : SELECT GetTextSetting('Test2'), INI_GetValue(GetSetting('Test2'), 'xxx', 'bbb'), INI_SetValue(GetSetting('Test2'), 'xxx', 'bbb', 'NEU'), INI_SetValue(GetSetting('Test2'), 'xxx', 'bbc', 'NEU')

  -- Zeile aus einem StringList-TEXT auslesen
  CREATE OR REPLACE FUNCTION SL_GetLine(list TEXT, line INTEGER) RETURNS VARCHAR AS $$
    --SELECT (regexp_matches(list, '^(.*)$', 'm'))[line]
    SELECT (regexp_split_to_array(list, '\\r?\\n'))[line]
  $$ LANGUAGE SQL IMMUTABLE;
  --

  -- Value aus einem StringList-TEXT auslesen -> Name=Value
  CREATE OR REPLACE FUNCTION SL_GetValue(list TEXT, name VARCHAR, defvalue VARCHAR DEFAULT '') RETURNS VARCHAR AS $$
    -- SELECT+regexp_matches liefert "keinen" Datensatz, wenn nichts gefunden wurde, daher das SUBSELECT mit COALESCE
    SELECT coalesce((SELECT (regexp_matches(list, '^' || name || '=(.*)$', 'mi'))[1]), defvalue)
  $$ LANGUAGE SQL IMMUTABLE;
  --

  -- Value in einem StringList-TEXT ändern -> Name=Value
  CREATE OR REPLACE FUNCTION SL_SetValue(list TEXT, name VARCHAR, value VARCHAR, defvalue VARCHAR DEFAULT '') RETURNS TEXT AS $$
  BEGIN
    -- altes weg
    list := regexp_replace(list, '^' || name || '=(.*)$', '', 'mi');
    -- neues rein
    IF (value <> '') and (value IS DISTINCT FROM defvalue) THEN
      list := concat(list, '\r\n', name, '=', value);
    END IF;
    -- sortieren
    RETURN trim(array_to_string(ARRAY(SELECT regexp_split_to_table(list, '\r?\n' , 'mi') ORDER BY 1), '\r\n'), ' \r\n');
  END $$ LANGUAGE plpgsql;
  --

  -- Value aus einem INI-TEXT auslesen -> [Section] Name=Value
  CREATE OR REPLACE FUNCTION INI_GetValue(ini TEXT, section VARCHAR, name VARCHAR, defvalue VARCHAR DEFAULT '') RETURNS VARCHAR AS $$
    -- SELECT+regexp_matches liefert "keinen" Datensatz, wenn nichts gefunden wurde, daher das SUBSELECT mit COALESCE
    --SELECT coalesce((SELECT (regexp_matches(ini, '^\\[' || section || '\\]\\s*$[^\\[]*^' || name || '=(.*)$', 'mi'))[1]), defvalue)

    -- Aus unerfindlichen Gründen funktioniert das Zeilenendematching nicht mehr, daher manuell die Zeilenumbrüche suchen http://www.delphipraxis.net/189708-regex-fehlerhafter-zeilenumbruch-postgresql.html
    SELECT coalesce((SELECT (regexp_matches('\\n' || ini || '\\n', '\\r?\\n\\[' || section || '\\][ \\t]*\\r?\\n?[^\\[]*\\r?\\n' || name || '=([^\\r\\n]*)\\r?\\n', 'i'))[1]), defvalue)
  $$ LANGUAGE SQL IMMUTABLE;
  --
  
  -- Value in einem INI-TEXT ändern -> [Section] Name=Value
  CREATE OR REPLACE FUNCTION INI_SetValue(ini TEXT, section VARCHAR, name VARCHAR, value VARCHAR, defvalue VARCHAR DEFAULT '') RETURNS TEXT AS $$
  DECLARE seA TEXT;
          seN TEXT;
  BEGIN
    /*
    -- altes weg ... der Lookbehind will nicht, wie er soll, also zuerst Section extrahieren und dann darin den Value entferen
    --ini := regexp_replace(ini, '(?<!^\\[' || section || '\\]\\s*$[^\\[]*)^' || name || '=(.*)$', '', 'mi');
    seA := (regexp_matches(ini, '^(\\[' || section || '\\]\\s*$[^\\[]*^' || name || '=.*)$', 'mi'))[0];
    seN := regexp_replace(seA, '^' || name || '=.*$', '', 'mi');
    IF seA <> '' THEN
      ini := replace(ini, seA, seN);
    END IF;
    -- neues rein
    IF regexp_matches(ini, '^\\[' || section || '\\]\\s*$', 'mi') IS NOT NULL THEN
    ELSE
      ini := concat(ini, '\r\n[', section, ']');
    END IF;
    IF (value <> '') and (value IS DISTINCT FROM defvalue) THEN
      ini := regexp_replace(ini, '^\\[' || section || '\\]\\s*$', concat('[', section, ']\r\n', name, '=', value), 'mi');
    END IF;
    -- fertig
    RETURN trim(regexp_replace(ini, '\\r?\\n([ \\t]*\\r?\\n)+', '\r\n', ''), ' \r\n');
    */


    -- Aus unerfindlichen Gründen funktioniert das Zeilenendematching nicht mehr, daher manuell die Zeilenumbrüche suchen http://www.delphipraxis.net/189708-regex-fehlerhafter-zeilenumbruch-postgresql.html
    ini := '\n' || ini || '\n';
    -- altes weg
    seA := (regexp_matches(ini, '(\\r?\\n\\[' || section || '\\][ \\t]*\\r?\\n?[^\\[]*\\r?\\n' || name || '=([^\\r\\n]*)\\r?\\n)', 'i'))[1];
    seN := regexp_replace(seA, '^' || name || '=.*$', '', 'mi');
    IF seA <> 'THEN
      ini := replace(ini, seA, seN);
    END IF;
    -- neues rein
    IF regexp_matches(ini, '\\r?\\n\\[' || section || '\\][ \\t]*\\r?\\n', 'i') IS NOT NULL THEN
    ELSE
      ini := concat(ini, '\r\n[', section, ']\r\n');
    END IF;
    IF (value <> '') and (value IS DISTINCT FROM defvalue) THEN
      ini := regexp_replace(ini, '\\r?\\n\\[' || section || '\\][ \\t]*\\r?\\n', concat('\r\n[', section, ']\r\n', name, '=', value, '\r\n'), 'i');
    END IF;
    -- fertig
    RETURN trim(regexp_replace(ini, '\\r?\\n([ \\t]*\\r?\\n)+', '\r\n', ''), ' \r\n');
  END $$ LANGUAGE plpgsql;
  --

--
$2B or not $2B
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:49 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz