正则表达式匹配文件和分组中的部分

时间:2017-08-03 11:06:20

标签: python regex parsing

我有一个以下格式的文本文件:

*CMD1,I1=0,I2=0,I3=0
*CMD2,I1=0,I2=1,I3=2
1,2,3
4,5,6
*CMD3,U1=0,U2=9,U3=8
4,5,6
3,4,6
*CMD3,U4=0
par,1,2
par,3,4

我想制作一个键值对。键是以*开头的行,值是下面的列表(所有内容,无论类型等等)。

我正在使用正则表达式来完成此任务。

我相信捕获以*开头的行的表达式是:

r'^ *\*.*'

这是我的代码:

import re, mmap, os

with open(fn,'r') as fin:
    size = os.stat(fn).st_size
    data = mmap.mmap(fin.fileno(), size, access=mmap.ACCESS_READ)
    for m in re.finditer(r'^( *\*.*)(...)',data,re.M)
        print 1
        print m.group(1)
        print 2
        print m.group(2)

输出的(...)占位符应该是什么:

1
*CMD1,I1=0,I2=0,I3=0
2

1
*CMD2,I1=0,I2=1,I3=2
2
1,2,3
4,5,6

1
*CMD3,U1=0,U2=9,U3=8
2
4,5,6
3,4,6

1
*CMD3,U4=0
2
par,1,2
par,3,4

5 个答案:

答案 0 :(得分:0)

以下是有效的正则表达式:(\*[\w,=]*)([\s\w,]*)

<强>说明: 此正则表达式有两个组:第一个(\*[\w,=]*)用于键,仅匹配以“*”开头的任何行,而第二个([\s\w,]*)匹配所有不以“*”开头的行。请注意,您必须删除值以删除不需要的空格。

<强>输出:

Match 1
1. *CMD1,I1=0,I2=0,I3=0 
2.  

Match 2
1. *CMD2,I1=0,I2=1,I3=2 
2.  1,2,3 4,5,6  

Match 3
1. *CMD3,U1=0,U2=9,U3=8 
2.  4,5,6 3,4,6  

Match 4
1. *CMD3,U4=0 
2.  par,1,2 par,3,4 

答案 1 :(得分:0)

  

我想制作一个键值对。

我不认为正则表达式是实现目标的最佳方式。遍历这些行,将集合中的键设置为以'*'开头的行,并将不以'*'开头的行附加到值。

current_key = None
data_map = {}
for line in data.split('\n'):
    if line.startswith('*'):
        current_key = line
        data_map[current_key] = []
    else:
        if current_key is None:
            continue #no known key above, skip
        data_map[current_key].append(line)

然后获取您的打印输出:

>>>for k, v in data_map.items():
        print(1)
        print(k)
        print(2)
        print(*v, '\n', sep = '\n')


1
*CMD3,U4=0
2
par,1,2
par,3,4


1
*CMD3,U1=0,U2=9,U3=8
2
4,5,6
3,4,6


1
*CMD1,I1=0,I2=0,I3=0
2


1
*CMD2,I1=0,I2=1,I3=2
2
1,2,3
4,5,6

答案 2 :(得分:0)

请原谅我这么直率但不需要正则表达式。你可以更简单地做到这一点。检查&#39; *&#39;的外观。一行开头的字符,并据此采取行动。

>>> begun = False
>>> with open('temp.txt') as text:
...     for line in text.readlines():
...         if not line:
...             break
...         line = line.strip()
...         if line.startswith('*'):
...             if begun:
...                 print ()
...             else:
...                 begun = True
...             print (1)
...             print (line)
...             print (2)
...         else:
...             print (line)
...             
1
*CMD1,I1=0,I2=0,I3=0
2

1
*CMD2,I1=0,I2=1,I3=2
2
1,2,3
4,5,6

1
*CMD3,U1=0,U2=9,U3=8
2
4,5,6
3,4,6

1
*CMD3,U4=0
2
par,1,2
par,3,4

答案 3 :(得分:0)

正如其他人发布的那样,str.startwith('*')足以检测一行是否以'*'开头。作为Raymond Hettinger在itertoolsgroupby中工作的粉丝,我提供了这种迭代几个群体的方法:

from itertools import groupby

def generate_groups(text):

    key_fn = lambda s: s.startswith('*')

    last = None
    for leading_star, following in groupby(text.splitlines(), key=key_fn):
        if not leading_star:
            # multiple rows not starting with '*', these are subs of last '*' row
            yield (last, list(following))
            last = None
        else:
            # multiple rows starting with '*'
            for f in following:
                if last is not None:
                    yield (last, [])
                last = f

    if last is not None:
        yield (last, [])

print(sample)
for group in (generate_groups(sample)):
    print(group)

打印

*CMD1,I1=0,I2=0,I3=0
*CMD2,I1=0,I2=1,I3=2
1,2,3
4,5,6
*CMD3,U1=0,U2=9,U3=8
4,5,6
3,4,6
*CMD3,U4=0
par,1,2
par,3,4

('*CMD1,I1=0,I2=0,I3=0', [])
('*CMD2,I1=0,I2=1,I3=2', ['1,2,3', '4,5,6'])
('*CMD3,U1=0,U2=9,U3=8', ['4,5,6', '3,4,6'])
('*CMD3,U4=0', ['par,1,2', 'par,3,4'])

答案 4 :(得分:-1)

我尝试for m in re.finditer(r'^( *\*.*)([^*]+)',data,re.M):并且它似乎提供了有效的结果,使用strip()修剪任何空格并且可以找到确切的输出,

1

* CMD1,I1 = 0,I2 = 0,I3 = 0

2

1 * CMD2,I1 = 0,I2 = 1,I3 = 2

2

1,2,3

4,5,6

1

* CMD3,U1 = 0,U2 = 9,U3 = 8

2

4,5,6

-3,4,6-

1

* CMD3,U4 = 0

2

参数,1,2-

参数,3,4-