Python 正则表达式以匹配文件和分组中的节

Python 正则表达式以匹配文件和分组中的节,python,regex,parsing,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 我想做一个键值对。键是以*开头的行,值是下面的列表(所有内容,无论类型等) 我使用regex就是为了完成这个任务 我认为用*开头的行来表示: r'^ *\*.*' 这是我的密码: import re, mmap, os with ope

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

*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
我想做一个键值对。键是以*开头的行,值是下面的列表(所有内容,无论类型等)

我使用regex就是为了完成这个任务

我认为用*开头的行来表示:

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

下面是有效的正则表达式:
(\*[\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 

我在re.finditer(r'^(*\*.*)([^*]+)、data、re.m中尝试了
,它似乎给出了有效的结果,使用
strip()
修剪任何空白,可以找到确切的输出

一,

*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

二,

标准杆,1,2

标准杆,3,4

我想做一个键值对

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

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

请原谅我的直言不讳,但没有必要使用正则表达式。你可以做得更简单一些。检查行首是否出现“*”字符,并采取相应措施

>>> 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

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

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

@谢谢你的提示,billy,就我所知,我已经做了建议的更改,如果有不同/更好的方法,请分享我不确定,问对不对,因为尽管得到了正确的结果,但答案被标记为无效,我想知道我的解决方案是否错误,