2016-03-24 11 views
0

特にフォーマットされた区切りファイルを解析するためにcsvモジュールを使用しようとしています。私はPython 3.5を使用しています。Pythonのcsvモジュールを使用してテキストファイルを解析する問題

この形式は第三者によって提供されており、すべての場合にcsvモジュールを使用して表現することに問題があります。テキスト・データ型として指定された列は、二重引用符で囲まれた値を持ちます。日付と数値には、パイプ(デリミタ)の間に見積もり値はありません。問題は、複数のフォーマットを試してみると、1つの真ん中の二重引用符を残すか、\ - >空白のような情報を失うという点で問題が発生します。私はこのために正規表現を使用する必要はないと思っています。したがって、csvモジュールを使用する方法があれば、それは素晴らしいでしょう。

ルール:

エスケープ文字は "\"

  • タブのエスケープです:\トン
  • 改行文字:\ nは
  • バックスラッシュ文字:\\
  • 内側の引用文字:\ "
  • 区切り文字= |
  • 日付にはqがありませんuotes。私は様々な方言のパラメータをしようとするとNaN値(空のパイプ||)を含む
  • 数字は、私が正しく、このcsvファイルを解析することができないよう、何の引用符

を持っていません。バックスラッシュを空白に変換したり、内部引用符を間違って配置したりするなど、csvモジュールを使用する方法はありますか、後処理を行うか、独自の正規表現を作成する必要がありますか?

import csv 
import os 

dialect_params = {'delimiter': '|'} # help needed here. 

newline_sample = '"I went to dinner. \n Then I went to a show."' 
quote_sample = '"I read the \"WSJ\", did you?"' 
backslash_sample = '"Boasberg\\Wheeler Communications, Inc."' 
na_sample = 'N\A' 
date_sample = '2013-04-23' 
number_sample = '1.3' 
text_sample = '|'.join([newline_sample, quote_sample, 
         backslash_sample, na_sample, 
         date_sample, number_sample]) + '\n' 

csv.reader(iter([text_sample]), **dialect_params) 
+0

このコードは正しいですか?定義された 'lines'が見えません。 – strubbly

+0

「backspace」と言うとバックスラッシュを意味しますか?私はあなたがそれに何らかの問題を抱えていることに驚いています:csv形式は、デフォルトでバックスラッシュを特別なものにしません。 – strubbly

+0

あなたの 'quote_sample'に本当にリテラル' \ "'または単なる引用符(Pythonは後者を与えるでしょうか)をしたいのですか? – strubbly

答えて

0

あなたはPythonであなたの入力ファイルにエスケープし、エスケープを区別していないと、残念ながら、彼らはかなり似ているので、あなたの例では、いくつかの混乱があります。あなたのファイルにはリテラルの円記号が含まれているようですが、あなたのPythonの例はそうではありません。 Pythonでは、この文字列'"\""'は3文字で、3文字はすべて二重引用符であることに注意してください。

これは、コードをテストしようとすると混乱することもあります。たとえば、コードが入力内のバックスラッシュ文字の組を出力内の単一のバックスラッシュに変換すると、printreprの出力(リスト内など)の場合、再び2つのバックスラッシュが表示されます。

# A five character string consisting of two quotes, a backslash, a 
# newline and another quote 
s = '"\"\\\n"' 
print(s) 
# prints: 
# ""\ 
# " 
print([s]) 
# prints: 
# ['""\\\n"'] 

最も簡単な修正点は、テストコードに「生の」文字列を使用することです。出力を解釈するときは注意してください。

# An eight character string with a lot of backslashes in 
s = r'"\"\\\n"' 
print(s) 
# prints: 
# "\"\\\n" 
print([s]) 
# prints: 
# ['"\\"\\\\\\n"'] 

OK、あなたはあなたのPythonのテストをクリーンアップする場合は、問題は何です:文字列定義の前に追加rに注意してください?問題は、区切り文字と囲み引用符を解析するためにcsvモジュールを使用することです。しかし、引用符には問題があります。引用符を解釈するようにcsvに指示すると、フィールド内でエスケープされた引用符が検出され、そこでフィールドが停止します。引用符をエスケープできることを伝えると、エスケープされた改行がエスケープされているかのように解釈されます(n文字)。

import csv 
import io 

sample = r'''"ab \" cd \n ef" 
"gh \\ ij \t kl"''' 

# by default we have 
# doublequote = True 
# quotechar = '"' 
# But this means that single quotes in the 
# field are treated as ending the field 
for l in csv.reader(io.StringIO(sample)): 
    print(l[0]) 

# Setting 
# doublequote = False 
# escapechar = '\' 
# handles the quote correctly but messes up the escaped newline 
for l in csv.reader(io.StringIO(sample),doublequote = False,escapechar = '\\'): 
    print(l[0]) 

# Setting 
# quotechar = None 
# works correctly for the delimiters but not escaping or quoting 
for l in csv.reader(io.StringIO(sample),quotechar = None): 
    print(l[0]) 

私はあなたが正しく区切り文字を解釈するのではなく、(最後の例のように)引用符を無視するcsvモジュールを使用することをお勧め。

次に、引用符で囲まれたフィールドを解釈する独自のコードを書くことができます。まず引用符を囲み、それらを削除します。次に、str.replace()を使用して、各エスケープシーケンスを目的の文字に置き換えます。ここに例があります:

import csv 
import io 

escapes = [ 
    (r'\t','\t'), 
    (r'\n','\n'), 
    (r'\\','\\'), 
    (r'\"','\"'), 
] 

sample = r'''"ab \" cd \n ef|12" 
"ij \\ kl \t mn"|"o"''' 

for l in csv.reader(io.StringIO(sample),delimiter = '|',quotechar = None): 
    l = [f if f[0] != '"' else f[1:-1] for f in l] 
    for old,new in escapes: 
     l = [f.replace(old,new) for f in l] 
    print(l) 

最後に、これを行うのは簡単な方法ですが、うまく機能しません。より巧妙な解決策があります。たとえば、ast.literal_evalは、これらのエスケープがPythonのエスケープと互換性があるため、codecsモジュールを使用することもできますが、あなたが何をしているのかわからない場合は、これらのエスケープを推奨しません。

+0

これまでの支援に感謝します。私は私の記述を整理した。理想的には、文字列変数を二重引用符で囲んだ一重引用符で返します。つまり、「WSJ」を読みましたか? 'これはcsvモジュールで実現可能か、手で何かする必要があるかのように見えるでしょうか?ソリューションは完全な引用符で囲まれていて、各フィールドの先頭と末尾の引用をストリップしているようです。二重引用符で囲みますが、内部引用符は\ "文字列のペアとして現れます。 –

+0

私の例はどのように解析されるべきですか? – strubbly

+0

Pythonで\ "は一重引用符を意味します。しかし、おそらく(?)入力ファイルにリテラルのバックスラッシュがあることを意味しますか? – strubbly

関連する問題