繁体   English   中英

python3:从编译模式中提取 IP 地址

[英]python3: extract IP address from compiled pattern

我想处理日志文件中的每一行,如果行与我的模式匹配,则提取IP地址。 有几种不同类型的消息,在下面的示例中,我使用的是 p1 and p2`。

我可以逐行读取文件,并且每一行都匹配每个模式。 但是由于可以有更多的模式,我想尽可能高效地做到这一点。 我希望将这些模式编译成一个 object,并且每行只匹配一次:

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'])

但上面的代码不起作用,它抱怨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
...

当我不知道它是p1p2 ,...时,如何打印匹配的 ip? 我想要的只是 IP。 我不在乎它匹配哪种模式。

您可以考虑安装出色的regex模块,该模块支持许多高级正则表达式功能,包括分支重置组,旨在完全解决您在此问题中概述的问题。 分支重置组由(?|...)表示。 对于 output,分支重置组内不同替代模式中相同位置或名称的所有捕获组共享相同的捕获组。

请注意,在下面的示例中,匹配的捕获组成为命名的捕获组,因此您无需遍历多个组来搜索非空组:

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

你为什么不检查哪个正则表达式匹配?

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]

那是因为您对两个组使用相同的组名

试试这个,这将给出组名 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 + ')')

命名捕获组必须具有不同的名称,但由于所有捕获组都旨在捕获相同的模式,因此在这种情况下最好不要使用命名捕获组,而只需使用常规捕获组并遍历匹配 object 中的组打印第一个非空组:

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

将 ip 地址有效性添加到已接受的答案中。 Altho import ipaddress & import socket应该是理想的方式,这段代码将解析主机,

import regex as re 
from io import StringIO



def valid_ip(address):
    try:
        host_bytes = address.split('.')
        valid = [int(b) for b in host_bytes]
        valid = [b for b in valid if b >= 0 and b<=255]
        return len(host_bytes) == 4 and len(valid) == 4
    except:
        return False
    
        
    
        

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

patterns = patterns = [
    'Registration from {ip} - Wrong password',
    'Call from {ip} rejected because extension not found'
] 

file = StringIO('''
Registration from 259.1.1.1 - Wrong password,
    Call from 1.1.2.2 rejected because extension not found
''')

pattern = re.compile('(?|%s)' % '|'.join(patterns).format(ip=ip_pattern))

list1 = []
list2 = []

for line in file:
    match = re.search(pattern, line)
    if match:
        list1.append(match['ip']) # List of ip address 
        list2.append(valid_ip(match['ip'])) # Boolean results of valid_ip 


for i in range(len(list1)):
        if list2[i] == False:
            print(f'{list1[i]} is invalid IP')
        else:
            print(list1[i])
259.1.1.1 is invalid IP
1.1.2.2

[Program finished]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM