python3:コンパイルされたパターンからIPアドレスを抽出する


8

ログファイルのすべての行を処理し、行がIPパターンに一致する場合は住所を抽出します。メッセージにはいくつかの種類がありますand。以下の例では、p1 p2` を使用しています。

ファイルを1行ずつ読み取ることができ、各行が各パターンに一致します。しかし、もっと多くのパターンが存在する可能性があるため、できるだけ効率的に実行したいと考えています。私はこれらのパターンを1つのオブジェクトにコンパイルし、各行に対して1回だけ一致させることを望んでいました。

import re

IP = r'(?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'

p1 = 'Registration from' + IP + '- Wrong password' 
p2 = 'Call from' + IP + 'rejected because extension not found'

c = re.compile(r'(?:' + p1 + '|' + p2 + ')')

for line in sys.stdin:
    match = re.search(c, line)
    if match:
        print(match['ip'])

しかし、上記のコードは機能しません。2 ip回使用されていると文句を言います。

私の目標を達成する最もエレガントな方法は何ですか?

編集:

@Dev Khadkaからの回答に基づいてコードを変更しました。

しかし、私はまだ複数のipマッチを適切に処理する方法に苦労しています。以下のコードは、p1に一致したすべてのIPを出力します。

for line in sys.stdin:
    match = c.search(line)
    if match:
        print(match['ip1'])

しかし、一部の行は一致しませんp1。彼らは一致しp2ます。つまり、次のようになります。

1.2.3.4
None
2.3.4.5
...

それがあったwheter私にはわからないときはどうすれば、一致するIPを印刷しますかp1p2...?私が欲しいのはIPだけです。どのパターンに一致したかは気にしません。


1
テストデータを提供する必要があります。
eyllanesc

回答:


4

この質問で概説した問題を正確に解決するように設計された、ブランチリセットグループregexを含む多くの高度な正規表現機能をサポートする優れたモジュールのインストールを検討できます。ブランチリセットグループはで示されます。ブランチリセットグループ内の異なる代替パターンの同じ位置または名前のすべてのキャプチャグループは、出力用に同じキャプチャグループを共有します。(?|...)

以下の例では、一致するキャプチャグループが名前付きキャプチャグループになるため、空でないグループを検索する複数のグループを反復処理する必要がないことに注意してください。

import regex

ip_pattern = r'(?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
patterns = [
    'Registration from {ip} - Wrong password',
    'Call from {ip} rejected because extension not found'
]
pattern = regex.compile('(?|%s)' % '|'.join(patterns).format(ip=ip_pattern))
for line in sys.stdin:
    match = regex.search(pattern, line)
    if match:
        print(match['ip'])

デモ:https : //repl.it/@blhsing/RegularEmbellishedBugs


1
これは完璧です!ありがとうございました。
Martin Vegter、

2

一致する正規表現を確認してみませんか?

if 'ip1' in match :
    print match['ip1']
if 'ip2' in match :
    print match['ip2']

または次のようなもの:

names = [ 'ip1', 'ip2', 'ip3' ]
for n in names :
    if n in match :
        print match[n]

あるいは

num = 1000   # can easily handle millions of patterns =)
for i in range(num) :
    name = 'ip%d' % i
    if name in match :
        print match[name]

しかし、100個のパターンがある場合はどうなりますか?これをループで実行できますか?match[i]forループでitterateできますか?
Martin Vegter、

@MartinVegter上記を参照
lenik '21 / 10/21

@MartinVegterは数百万のパターンを簡単に処理できます=)
lenik '21 / 10/21

エラーが表示されます:if match[name] is not None: IndexError: no such group
Martin Vegter

@MartinVegterがname in match代わりに使用を試みる
lenik '21

1

2つのグループに同じグループ名を使用しているため

これを試してください、これはグループ名ip1とip2を与えます

import re

IP = r'(?P<ip%d>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'

p1 = 'Registration from' + IP%1 + '- Wrong password' 
p2 = 'Call from' + IP%2 + 'rejected because extension not found'

c = re.compile(r'(?:' + p1 + '|' + p2 + ')')

1

名前付きキャプチャグループには異なる名前を付ける必要がありますが、すべてのキャプチャグループは同じパターンをキャプチャすることを目的としているため、この場合は名前付きキャプチャグループを使用せず、通常のキャプチャグループを使用して、一致オブジェクトのグループを反復処理することをお勧めします空でない最初のグループを印刷するには:

ip_pattern = r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
patterns = [
    'Registration from {ip} - Wrong password',
    'Call from {ip} rejected because extension not found'
]
pattern = re.compile('|'.join(patterns).format(ip=ip_pattern))
for line in sys.stdin:
    match = re.search(pattern, line)
    if match:
        print(next(filter(None, match.groups())))

デモ:https : //repl.it/@blhsing/UnevenCheerfulLight

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.