3

考えられる最も不均一な方法でフォーマットされたデータ (テキスト ファイル) があります。このデータの解析に関する手作業の量を最小限に抑えようとしています。

サンプルデータ :

Name        Degree      CLASS       CODE        EDU     Scores
--------------------------------------------------------------------------------------
John Marshall       CSC   78659944   89989        BE   900
Think Code DB I10   MSC  87782  1231  MS            878
Mary 200 Jones    CIVIL      98993483  32985        BE       898
John G. S  Mech 7653 54 MS 65
Silent Ghost  Python Ninja 788505  88448  MS Comp  887

条件 :

  • 複数のスペースは区切り文字に圧縮する必要があります (パイプの方が良いですか?最終的な目標は、これらのファイルをデータベースに格納することです)。
  • 最初の列を除いて、他の列にはスペースが含まれないため、これらのスペースはすべてパイプに圧縮できます。
  • スペースを含む複数の単語を含めることができるのは、最初の列のみです (Mary K Jones)。残りの列は、ほとんどが数字と一部のアルファベットです。
  • 1 列目と 2 列目は両方とも文字列です。ほとんどの場合、それらの間に複数のスペースがあるため、2 つの列を区別することができます。(単一のスペースがある場合、それは恐ろしい書式設定を考えると喜んで引き受けるリスクです!)。
  • 列の数はさまざまなので、列名を気にする必要はありません。必要なのは、各列のデータを抽出することだけです。

私が理にかなっていることを願っています!このタスクはワンライナーで実行できると感じています。ループ、ループ、ループしたくない:(

ずっと読んで、この文の前にやめないための「Pythonistas」のMuchos gracias!

4

3 に答える 3

3

あなたのファイルにはまだいくつかのフォーマットがあるようです:

>>> regex = r'^(.+)\b\s{2,}\b(.+)\s+(\d+)\s+(\d+)\s+(.+)\s+(\d+)'
>>> for line in s.splitlines():
    lst = [i.strip() for j in re.findall(regex, line) for i in j if j]
    print(lst)


[]
[]
['John Marshall', 'CSC', '78659944', '89989', 'BE', '900']
['Think Code DB I10', 'MSC', '87782', '1231', 'MS', '878']
['Mary 200 Jones', 'CIVIL', '98993483', '32985', 'BE', '898']
['John G. S', 'Mech', '7653', '54', 'MS', '65']
['Silent Ghost', 'Python Ninja', '788505', '88448', 'MS Comp', '887']

正規表現は非常に単純です。注意する必要があるのは、区切り文字( )と、最初の区切り文字の場合の\s単語区切り( )だけです。\b行が一致しない場合は、空のリストがとして表示されることに注意してくださいlst。これは、以下で説明するユーザーインタラクションを表示するための読み取りフラグになります。また、次のようにしてヘッダー行をスキップすることもできます。

>>> file = open(fname)
>>> [next(file) for _ in range(2)]
>>> for line in file:
    ...  # here empty lst indicates issues with regex

以前の亜種:

>>> import re
>>> for line in open(fname):
    lst = re.split(r'\s{2,}', line)
    l = len(lst)
    if l in (2,3):
        lst[l-1:] = lst[l-1].split()
    print(lst)

['Name', 'Degree', 'CLASS', 'CODE', 'EDU', 'Scores']
['--------------------------------------------------------------------------------------']
['John Marshall', 'CSC', '78659944', '89989', 'BE', '900']
['Think Code DB I10', 'MSC', '87782', '1231', 'MS', '878']
['Mary 200 Jones', 'CIVIL', '98993483', '32985', 'BE', '898']
['John G. S', 'Mech', '7653', '54', 'MS', '65']

もう1つのことは、ユーザーが疑わしいエントリをどうするかを決定できるようにすることです。

if l < 3:
    lst = line.split()
    print(lst)
    iname = input('enter indexes that for elements of name: ')     # use raw_input in py2k
    idegr = input('enter indexes that for elements of degree: ')

ええと、私はいつも、2番目の要素にスペースが含まれている可能性があるという印象を受けていました。

>>> for line in open(fname):
    name, _, rest = line.partition('  ')
    lst = [name] + rest.split()
    print(lst)
于 2010-10-06T15:30:15.933 に答える
2

SilentGhostの回答のバリエーション。今回は最初に残りの名前を分割し(2つ以上のスペースで区切る)、次に残りを分割し、最後に1つのリストを作成します。

import re

for line in open(fname):
    name, rest = re.split('\s{2,}', line, maxsplit=1)
    print [name] + rest.split()
于 2010-10-06T16:19:04.300 に答える
1

この回答は、OPがデータ内のすべてのタブ(「\ t」)を3つのスペースに変更することを告白した後に書かれました(彼の質問では言及していません)。

最初の行を見ると、これは固定列幅のレポートのようです。データにタブが含まれている可能性は十分にありますが、適切に展開すると、おかしくない結果になる可能性があります。

代わりにline.replace('\t', ' ' * 3)tryを実行しline.expandtabs()ます。

expandtabs のドキュメントはこちらです。

結果が理にかなっているように見える場合 (データの列が並んでいる場合)、プログラムで列幅を計算する方法を決定する必要があります (可能であれば) - おそらく見出し行から。

2 行目がすべて "-" になっていますか、それとも列の間にスペースがありますか? 質問する理由は、データベースクエリレポートメカニズムから多くの異なるファイルを解析する必要があったためです。結果は次のようになりました。

RecordType  ID1                  ID2         Description           
----------- -------------------- ----------- ----------------------
1           12345678             123456      Widget                
4           87654321             654321      Gizmoid

また、2 行目を調べて見出し行とデータ行をスライスする場所を決定する、完全に一般的なリーダーを作成することもできました。ヒント:

sizes = map(len, dash_line.split())

expandtabs() が機能しない場合は、質問を編集して、何を持っているかを正確に表示します。つまりprint repr(line)、最初の 5 行程度 (見出し行を含む) の結果を表示します。また、これらのファイルを生成するソフトウェアを教えていただけると助かります。

于 2010-10-07T20:43:12.333 に答える