Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu
Online

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

RegEx: fehlerhafter Zeilenumbruch (PostgreSQL)

  Alt 12. Jul 2016, 10: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.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

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