4

以下の文字列からいくつかの情報を抽出しようとしています

>>> st = '''
... <!-- info mp3 here -->
...                             192 kbps<br />2:41<br />3.71 mb  </div>
... <!-- info mp3 here -->
...                             3.49 mb  </div>
... <!-- info mp3 here -->
...                             128 kbps<br />3:31<br />3.3 mb   </div>
... '''
>>>

以下の正規表現を使用すると、出力は次のようになります

>>> p = re.findall(r'<!-- info mp3 here -->\s+(.*?)<br />(.*?)<br />(.*?)\s+</div>',st)
>>> p
[('192 kbps', '2:41', '3.71 mb'), ('128 kbps', '3:31', '3.3 mb')]

しかし、私の必要な出力は

[('192 kbps', '2:41', '3.71 mb'),(None,None,'3.49mb'), ('128 kbps', '3:31', '3.3 mb')]

だから、私の質問は、すべての条件に一致するように上記を変更する方法です.現在の正規表現はタグregexに厳密に依存していると信じているので、それを条件付きにする方法.<br />

HTMLを解析するために正規表現を使用すべきではないことはわかっていますが、現在これが私にとって最も適切な方法です。

4

2 に答える 2

6

以下は機能しますが、もっとエレガントな解決策がないのではないかと思います。リスト内包表記を 1 行にまとめることは確かにできますが、それではコード全体がわかりにくくなると思います。少なくとも、これで 3 か月後に何をしたかを追跡できるようになります...

st = '''
<!-- info mp3 here -->
                            192 kbps<br />2:41<br />3.71 mb  </div>
<!-- info mp3 here -->
                            3.49 mb  </div>
<!-- info mp3 here -->
                            128 kbps<br />3:31<br />3.3 mb   </div>
'''

p = re.findall(r'<!-- info mp3 here -->\s+(.*?)\s+</div>',st)
p2 = [row.split('<br />') for row in p]
p3 = [[None]*(3 - len(row)) + row for row in p2]

>>> p3
[['192 kbps', '2:41', '3.71 mb'], [None, None, '3.49 mb'], ['128 kbps', '3:31', '3.3 mb']]

また、文字列の変動性に応じて、より一般的なクリーニング関数を作成して、それをストリップ、ケースなどを抽出し、引き出す各アイテムにマップすることをお勧めします。

于 2012-05-24T20:33:56.140 に答える
2

これは、もう少し具体的にすることで機能する正規表現ソリューションです。これがKarmelの回答よりも好ましいかどうかはわかりませんが、尋ねられたとおりに質問に答えると思いました。を返す代わりにNone、最初の 2 つのオプション グループは空の文字列''を返します。これはおそらく十分に近いと思います。

ネストされたグループ構造に注意してください。最初の 2 つの外側のグループはオプションですが、<br />一致させるにはタグが必要です。そうすれば、タグが 2 つ未満の場合<br />、最後の項目は最後まで一致しません。

rx = r'''<!--\ info\ mp3\ here\ -->\s+   # verbose mode; escape literal spaces
         (?:                             # outer non-capturing group  
            ([^<>]*)                     # inner capturing group without <>
            (?:<br\ />)                  # inner non-capturing group matching br
         )?                              # whole outer group is optional
         (?:                             
            ([^<>]*)                     # all same as above
            (?:<br\ />)                
         )?
         (?:                             # outer non-capturing group
            (.*?)                        # non-greedy wildcard match
            (?:\s+</div>)                # inner non-capturing group matching div
         )'''                            # final group is not optional

テスト済み:

>>> re.findall(rx, st, re.VERBOSE)
[('192 kbps', '2:41', '3.71 mb'), 
 ('', '', '3.49 mb'), 
 ('128 kbps', '3:31', '3.3 mb')]

re.VERBOSE上記の空白とコメントをすべて削除しない限り必要なフラグに注意してください。

于 2012-05-24T20:48:05.773 に答える