Regulärer Ausdruck zum Abgleichen öffnender doppelter Anführungszeichen ohne schließende doppelte Anführungszeichen

Regulärer Ausdruck zum Abgleichen öffnender doppelter Anführungszeichen ohne schließende doppelte Anführungszeichen

Ich habe eine große (25 Millionen Zeilen) Datendatei, die durch Pipe-Zeichen ( |) getrennt ist. Der Datenanbieter stellt Dateien bereit und ich führe automatisierte Jobs aus, um die Dateien in eine Redshift-Datenbank zu laden und dann die Daten zu verarbeiten.

Nachfolgend sehen Sie ein Beispiel der Daten:

123|110092|ACCT|"HC Account"|"Account1||||||||||||"Mary"|||"|"||||132|"STE|504"|1253|Unspecified Account|||N||ACTV|Active||||04/30/2013|12/31/2099|||||||||||||

Es gibt drei Sätze von Felddaten, die ich bisher gesehen habe:

  1. Ein Textfeld ist in doppelte Anführungszeichen ( ") eingeschlossen. Beispiel: "HC Account", "Mary", und "|". Dies ist korrekt und die Daten sollten ohne Anführungszeichen geladen werden.
  2. Einige Werte enthalten das Pipe-Trennzeichen. Beispiel: "STE|504". In diesem Fall muss das Feld unbedingt in Anführungszeichen eingeschlossen werden. Ist dies nicht der Fall, fällt es in die folgende Kategorie drei.
  3. Manchmal wird nur ein Anfangszitat angegeben, aber kein Schlusszitat. Beispiel: "Account1.

TL;DR: Jedes Feld, das mit beginnt |", muss mit einem enden "|. Wenn dies nicht der Fall ist und ein weiteres |"gefunden wird, muss das erste Anführungszeichen maskiert werden.

Daher sollte meine Datenzeile so bearbeitet werden, dass sie wie folgt aussieht, nachdem ich sie in Unix/Python/anderen Vorschlägen vorverarbeitet habe:

123|110092|ACCT|"HC Account"|"Account1||||||||||||"Mary"|||"|"||||132|"STE|504"|1253|Unspecified Account|||N||ACTV|Active||||04/30/2013|12/31/2099|||||||||||||


Ich habe vor, ein Unix-Skript zu schreiben, um die Datei mit SED zu ändern. Der reguläre Ausdruck, den ich bisher geschrieben habe, ist:

(\|")(?!([a-zA-Z0-9]|\s|\||\/)*("\|))

Allerdings wird die Zeichenfolge dadurch nicht richtig abgeglichen.

Hier ist ein Link dorthin, wo ich das teste:https://regexr.com/3toib

Ich möchte den Code möglichst klein halten, da eine durchschnittliche Datei 3–5 GB groß ist und es normalerweise mehrere (10+) solcher Dateien gibt.

PS Redshift ist ein AWS-Datenbankdienst, der die Postgre SQL Engine verwendet und in der Lage ist, Anführungszeichen aus korrekt zitierten Feldern zu entfernen und die besondere Bedeutung eines Anführungszeichens mit zu maskieren \.

Außerdem bin ich bereit, dies in Python/einer anderen Skriptsprache zu tun, sofern der Code leicht ist.

Antwort1

Es gibt ein RIESIGES Problem mit den Spezifikationen, die Sie für die Daten angegeben haben. Wenn es "|"sich um eine gültige Zeichenfolge handelt, oder genauer gesagt, wenn eine Zeichenfolge in Anführungszeichen mit einem Pipe-Zeichen beginnen darf, dann gibt es keine Möglichkeit, festzustellen, ob eine Zeichenfolge mit einem fehlenden Anführungszeichen am Ende, z. B. "Account1, als erstes folgendes Feld in Anführungszeichen eines hat, das mit einem Pipe-Zeichen beginnt, z. B. ."|Mary"auf alle Fällewenn dies "|das Endanführungszeichen für |"Account1||||||||||||"|oder das Anfangsanführungszeichen für ist |"|Mary"|.

Beispielsweise könnte man eine verkürzte (zur besseren Lesbarkeit) und leicht modifizierte Version der Daten verwenden, bei der alle in Anführungszeichen gesetzten Zeichenfolgen ab der zweiten mit einem senkrechten Strich beginnen und die Anführungszeichen am Ende fehlen.

123|110092|ACCT|"HC Account"|"Account1||||||||||||"|Mary|||"|||||132|"|STE|504|1253

Es ist ersichtlich, dass dies fälschlicherweise interpretiert wird als

123 110092 ACCT "HC Account" "Account1||||||||||||" Mary   "|||||132|" STE 504 1253

Beachten Sie, dass dies ein Problem ist, egal ob Sie Regexes, Python oder eine andere Sprache verwenden. Das allgemeine Fallproblemdürfen„gelöst“ werden, aber es wird kompliziert sein und erfordert Kenntnisse darüber, wie viele Felder pro Zeile vorhanden sind und welche Datenstruktur diese Felder haben. (Und es kann immer Randfälle geben, die unberücksichtigt bleiben.)


Allerdings ist eine Regex-Lösung, die zumindest erkenntam meistenFälle, in denen ein öffnendes Anführungszeichen ein schließendes Anführungszeichen fehlt, erfordern einen mehrstufigen Ansatz, da der reguläre Ausdruck den gesamten Text vom Anfang jeder Zeile bis zum ersten unverarbeiteten, nicht übereinstimmenden öffnenden Anführungszeichen erfassen muss. (Andernfalls werden, wie Ihr regulärer Ausdruck zeigt, selbst in den einfachsten Fällen falsche Positivergebnisse gefunden.)

Die Anzahl der erforderlichen Durchläufe ist die maximale Anzahl von Feldern, die nur Anführungszeichen enthalten, für jede Zeile in der gesamten Datei plus eins. Um die Verarbeitung jeder Datei zu beenden, muss erkannt werden, wann der reguläre Ausdruck keine weiteren Änderungen an der Datei vornimmt.

Dies ist der einfachste reguläre Ausdruck, der in den meisten Fällen funktioniert:

                    Capturing Group 1           Capturing Group 2
               (All previous valid fields)  (Unclosed opening quote)
  __________________________|_________________________  |
 |                                                    || |
^((?:(?:(?!")[^|\r\n]*|"[^"\r\n]*"(?=$|\|))(?:$|\|))*+)(")
        |____________| |_________________| |______|
              |                 |              |
      Unquoted field  OR  Quoted field     EOL or hypen delimiter

Verwenden Sie es mit dieser Ersetzungszeichenfolge:

$1\\$2

Demo

verwandte Informationen