終了二重引用符がない開始二重引用符に一致する正規表現

終了二重引用符がない開始二重引用符に一致する正規表現

パイプ ( ) で区切られた大きな (2,500 万行) データ ファイルがあります|。データ ベンダーがファイルを提供し、自動化されたジョブを実行してファイルを Redshift データベースにロードし、データを処理します。

以下はデータのサンプルです。

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

これまでに見たフィールド データには次の 3 セットがあります。

  1. テキスト フィールドは二重引用符 ( ") で囲まれています。例: "HC Account"、、"Mary"および"|"。これは正しいので、引用符なしでデータをロードする必要があります。
  2. 一部の値にはパイプ区切り文字が含まれます。例: "STE|504"。この場合、フィールドは必ず二重引用符で囲む必要があります。そうでない場合は、以下のカテゴリ 3 に分類されます。
  3. 場合によっては、開始引用符のみが提供され、終了引用符が提供されないことがあります。例: "Account1

TL;DR: で始まるフィールドは|"、 で終わる必要があります"|。 そうでない場合、別のフィールド|"が見つかったときは、最初の二重引用符をエスケープする必要があります。

したがって、Unix/Python/その他の提案で前処理した後、データ行は次のように編集されるはずです。

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


SED を使用してファイルを変更する Unix スクリプトを作成する予定です。これまでに作成した正規表現は次のとおりです。

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

ただし、これでは文字列を正しく一致させることができません。

私がこれをテストしている場所へのリンクは次のとおりです:https://regexr.com/3toib

平均的なファイルのサイズは 3 ~ 5 GB で、通常はそのようなファイルが複数 (10 個以上) あるため、コードを軽量に保ちたいと考えています。

PS Redshift は、Postgre SQL エンジンを使用する AWS データベースサービスであり、適切に引用符で囲まれたフィールドから引用符を削除し、引用符の特殊な意味を でエスケープすることができます\

また、コードが軽量であれば、Python やその他のスクリプト言語でこれを行うこともできます。

答え1

データに指定した仕様には、大きな問題が 1 つあります。 が"|"有効な文字列である場合、またはより正確には、引用符で囲まれた文字列はパイプで始まることが許可されている場合、たとえば のように、終了引用符のない文字列の"Account1最初の引用符フィールドがパイプで始まる場合、たとえば のよう"|Mary"に、それを判別する方法がありません。いずれの場合も"|の終了引用符であるか|"Account1||||||||||||"|、 の開始引用符であるか|"|Mary"|

たとえば、読みやすくするために、引用符で囲まれた2番目以降の文字列はすべてパイプで始まり、最後の引用符が省略されている、データの短縮版(読みやすくするために)を少し変更したバージョンを使用すると、

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

これは次のように誤って解釈されることがわかる。

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

これは正規表現、Python、その他の言語のいずれを使用しても問題となることに注意してください。一般的なケースの問題できる「解決」される可能性はありますが、複雑であり、行ごとにいくつのフィールドが存在するか、およびそれらのフィールドのデータ構造に関する知識が必要になります。(そして、対応されていないエッジケースが常に存在する可能性があります。)


そうは言っても、少なくとも検出できる正規表現ソリューションはほとんど開き二重引用符に閉じ引用符がない場合、正規表現は各行の先頭から最初の未処理の一致しない開き引用符までのすべてのテキストをキャプチャする必要があるため、マルチパス アプローチが必要になります。(そうしないと、正規表現が示すように、最も単純なケースでも誤検知が見つかります。)

必要なパスの数は、ファイル全体の任意の行の開始引用符のみのフィールドの最大数に 1 を加えた数です。各ファイルの処理を終了するには、正規表現がファイルにそれ以上変更を加えなくなったことを検出する必要があります。

これは、ほとんどの場合に機能する最も単純な正規表現です。

                    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

次の置換文字列と共に使用します:

$1\\$2

デモ

関連情報