非贪婪的换行符与re.DOTALL匹配

时间:2016-01-19 10:51:11

标签: python regex

我试图在Python中重现这个正则表达式:https://regex101.com/r/tP1bS4/2

示例entry数据如下:

[ 10.0.7.58/54648 -> 31.221.26.40/80 (http response) ]-
|
| server   = 31.221.26.40/80
| app      = ???
| lang     = none
| params   = anonymous
| raw_sig  = 1:Content-Type,?Last-Modified,?Cache-Control,?Expires,Date,Connection=[keep-alive]:Keep-Alive,Accept-Ranges:
|

基本上我想最终得到一个包含两个元素的组:服务器IP和端口,从第三行开始。

这是我的Python尝试;

server = re.findall( '\| server[ \s]+= (.*)\/(.*)\n', entry, re.DOTALL)
print server

这给了我server组:

[('31.221.26.40', '80\n| app      = ???\n| lang     = none\n| params   = anonymous\n| raw_sig  = 1:Content-Type,?Last-Modified,?Cache-Control,?Expires,Date,Connection=[keep-alive]:Keep-Alive,Accept-Ranges:\n|')]

正如您所看到的那样,\n没有分裂。预期结果将是:

[('31.221.26.40', '80')]

3 个答案:

答案 0 :(得分:2)

我会尝试 -

re.findall(r'\| server[ \s]+= (.*)\/([^\/\W]*)',string)

Demo

空间规范化\|\s*server\s*=\s*([^/]*?)/([^/\W]*)

更强大

答案 1 :(得分:2)

让我清楚一些事情。 re.DOTALL修饰符使.符号匹配任何符号,包括换行符。带有DOTALL的.*子模式将字符串与结尾匹配。

如果您使用'\| server[ \s]+= (.*)\/(.*)\n',则第一个.*匹配到最后/,第二个.*匹配到最后\n,因为它是贪婪(也就是说,引擎会抓取所有其余的字符串,然后回溯以试图适应后续的子模式)。

由于您的数据在一行中,因此 希望.与换行符匹配。因此,解决问题的最简单方法是使用

server = re.findall(r'\|\s*server\s*=\s*(.*?)/(.*)', entry)

请参阅regex demo

然而,只有当我们不知道期望什么字符时,点匹配才有用。您可以使用字符类来增强正则表达式:

server = re.findall(r'\|\s*server\s*=\s*([^\s/]+)/(\d+)', entry)

另一个regex demo(注意效率提高了x2倍)

([^\s/]+)匹配空格以外的1个或多个字符,而/\d+匹配1位或更多位数。

答案 2 :(得分:0)

没有正则表达式:

import io

data = '''[ 10.0.7.58/54648 -> 31.221.26.40/80 (http response) ]-
|
| server   = 31.221.26.40/80
| app      = ???
| lang     = none
| params   = anonymous
| raw_sig  = 1:Content-Type,?Last-Modified,?Cache-Control,?Expires,Date,Connection=[keep-alive]:Keep-Alive,Accept-Ranges:
|'''


for line in io.StringIO(data):
    if line.startswith('| server '):
        print(line[13:].rstrip().split('/'))

如果您不确切知道“server”之后的空格或制表符的数量,您可以这样更改:

if line.startswith('| server'):
    print(line.split()[3].split('/'))