2017-01-12 5 views
2

大きなパイプ "|"を処理しようとしていますが、二重引用符で囲まれたテキストファイル(> 700,000レコード、レコードごとに3000文字以上、レコードごとに28フィールド)を使用します。 Pythonスクリプトを使用します。 csvパーサーが、エスケープされていない二重引用符文字とファイル内のフィールドのテキスト内に埋め込まれたパイプのためにフィールドを誤って解析しているため、問題が発生しました。タブはファイルに存在しないので、二重引用符 - 二重引用符の区切り文字/修飾子文字列( "|")をタブ(\ t)に置き換えることで、タブ区切りファイルに変換したいと考えています。すべてのフィールドに値が設定されていても、フィールドに値が設定されていない場合は、比較的簡単です。ポピュレートされていないフィールドは空文字列で表されます。したがって、1から7までのパイプ区切り文字を二重引用符で始まる順序で並べることができます。テキストファイル内の区切り文字を代替文字で置き換えてください

簡単な例は次のとおりです。

"abc"|"2016-07-30"|"text narrative field"|"2016-08-01"|"123"|"456"|"789"|"EOR" 

より多くの代表的な例は次のとおりです。私は、各パイプ文字/二重引用符の組み合わせまたはシーケンスを置き換えます正規表現を書き込もうとしてきた

"abc"|"2017-01-01"|"height: 5' 7" (~180 cm) | weight: 80kg | in good health"|"2016-01-10"||||"EOR" 

パイプ文字の直後に二重引用符が1つ続いています(TAB文字の場合は1)。私は、繰り返し文字列を1文字で置き換えるための数多くの正規表現の例を見つけましたが、一連の繰り返し文字を同じ文字列の長さ文字列に置き換えるものはありません。

私は以下の正規表現を試しました:"\|{1,}"これは単一パイプのcharに対して機能しますが、複数のパイプを1つのTabで順に置き換えます。

  • 「($)ラインの二重引用符/エンドを削除
  • ライン/二重引用符(^)」の

    • 削除開始をし、二重引用符/パイプを交換する:私はまた、次の関連の側面を処理する必要がありますパイプ文字と同じ数のTAB文字を持つ行(1つ以上)/行末(たとえば "\ | $")

    正規表現の適用後の出力レコードは、\ t〜タブ文字を表します。

    abc\t2016-07-30\ttext narrative field\t2016-08-01\t123\t456\t789\tEOR 
    abc\t2017-01-01\theight: 5' 7" (~180 cm) | weight: 80kg | in good health\t2016-01-10\t\t\t\tEOR 
    

    あなたが"|"を探しているので、私はSEDやawkの

  • +0

    を試してみてください - 「祈る氏バベッジ、あなたは機械間違った数字に入れた場合、正しい答えが出てくるでしょうか? "あなたのファイルに有効なコンマ区切りの値がない場合、不正な出力に対してcsvパーサーを責めるのは少し難しいです:P – TessellatingHeckler

    +0

    これはパーサーに依存します。たとえば、Informaticaは上記のとおり、より複雑なレコードを正しく解析します。しかし、少なくとも私の意見では、CSVパーサはそうではありません。 'フィールド1:abc' 'フィールド2:2017-01-01 ' 'フィールド3:高さ:5 '7 "(〜180 cm)|重量:80kg |良いhealth' 'フィールド4: 'フィールド1:2017-01-01' 'フィールド3:高 'フィールド2 abc' 2016-01-10' ...しかし、それはにそれを解析します。フィールド4:重量:80kg「 」フィールド5:健康状態「 フィールド6:2016-01-10」 つまり、「他にも文字の前にchars | –

    答えて

    1
    import re 
    
    def count_pipes_in_regex_match(m): 
        # regex capture group should only contain pipe chars 
        matched_pipes = m.groups()[0] 
    
        return '\t' * len(matched_pipes) 
    
    
    # test string 
    s='"abc"|"2017-01-01"|"height: 5\' 7" (~180 cm) | weight: 80kg | in good health"|"2016-01-10"||||"EOR"' 
    
    
    # replace leading or trailing quotes 
    s = re.sub('^"|"$', '', s) 
    
    # replace quote pipe(s) quote 
    # or  quote pipe(s) end-of-string 
    # with as many tabs as there were pipes 
    s = re.sub('"(\|+)("|$)', count_pipes_in_regex_match, s) 
    
    print repr(s) #repr to show the tabs 
    

    は、CSVパーサが*間違ってフィールドを解析している* online at repl.it

    +1

    非常に迅速かつエレガントに答えた。ありがとうございました! –

    1

    を使用してpythonでまたはLinuxのいずれかでこれを解決するためのオープンだが|""|で複数||を交換する答えではないのですか?あなたは、その後のタブで"|"を置き換えることができ、この後

    while True: 
        new_data = re.sub(r'\|\|', '|""|', data) 
        if data == new_data: 
         break 
        data = new_data 
    

    :方法について

    +0

    アイデアありがとうございました。私はそれが引用符修飾されたテキストに埋め込まれた複数の順次パイプがあるため、この場合には動作しないと思いますフィールド。例えば。 "体重||はより多くの体液を必要とする"。幸いにも、テキストフィールドのパイプの直前または直後に二重引用符を含む文字シーケンスはありません。 –

    +0

    倍数があるという事実は私の例がループを持つ理由です。私の例が実行された後、それを試してみてください。あなたは '' | ''を置き換える正規表現を探しています。 –

    +0

    私は試して結果を投稿します。ありがとうございました。 –

    1

    3回通過することができます。

    1. "|"(および端に|)に|""|
    2. 分割して、すべての||を交換し、各分野から引用符を削除します。

    次のように:

    import re 
    
    for line in file: 
        while '||' in line: 
         line = line.replace('||', '|""|') 
    
        fields = re.split('^\||\|$|"\|"', line) 
    
        new_line = '\t'.join([field.strip('"') for field in fields]) 
    
    +0

    二重引用符で囲まれたテキストフィールドにパイプが埋め込まれているため、これは機能しません。つまり、パイプを埋め込んだ単一のテキストフィールドを別のフィールドに解析する必要はありません。 –

    +0

    本当に、パイプを引用符で囲むようにコードを更新しました。 – MattMS

    関連する問題