如何根据行数来确定组的数量?

时间:2016-08-19 09:11:06

标签: python regex python-3.x split

我有这个正则表达式:^:([^:]+):([^:]*),就像在this regex101 link中一样。

现在,在Python中,我有这个:

def get_data():
    data = read_mt_file()
    match_fields = re.compile('^:([^:]+):([^:]*)', re.MULTILINE)

    fields = re.findall(match_fields, data)

    return fields

对于包含regex101数据的文件,返回:

[('1', 'text\ntext\n\n'), ('20', 'text\n\n'), ('21', 'text\ntext\ntext\n\n'), ('22', ' \n\n'), ('25', 'aa\naa\naaaaa')]

现在,这没关系,但我想更改正则表达式,以便我可以根据行数来获得组的数量。含义:

  • 第一行,现在,我得到两组:
    1. 1
    2. text\ntext\n\n

我想改为:

  1. 1
  2. ((text\n),(text\n\n))< - 这些应该以某种方式存在于同一个组中但是分开,每个都在他自己的子组中。不知怎的,我需要知道它们都属于1字段,但是是sepparate lines。
  3. 所以,在python中,该文件的所需结果是:

    [('1', '(text\n), (text\n\n)'), ('20', 'text\n\n'), ('21', '(text\n), (text\n), (text\n\n)'), ('22', ' \n\n'), ('25', '(aa\n), (aa\n), (aaaaa)')]
    

    正则表达式可以实现吗?这可以通过一些不错的字符串操作来实现吗?

2 个答案:

答案 0 :(得分:0)

要做你想做的事,你需要另一个正则表达式。 这是因为re.match仅匹配它匹配的最后一项:

>>> re.match(r'(\d)+', '12345').groups()
('5',)

而不是使用一个正则表达式,你需要使用两个。 您正在使用的那个,然后使用re.findall来匹配所有“子组”。 您可以通过简单匹配非\n的任何内容以及任意数量的\n来获取这些子组。

因此,您可以使用[^\n]+\n*

等正则表达式
>>> re.findall(r'[^\n]+\n*', 'text\ntext')
['text\n', 'text']
>>> re.findall(r'[^\n]+\n*', 'text\ntext\n\n')
['text\n', 'text\n\n']
>>> re.findall(r'[^\n]+\n*', '')
[]

答案 1 :(得分:0)

您可以使用一个简单的技巧:在与正则表达式匹配后,对第2组值运行dotXpos = [?] * screenXpixels; dotYpos = [?] * screenYpixels; 正则表达式:

.+\n*

在这里,

  • import re p = re.compile(r'^:([^:]+):([^:]+)', re.MULTILINE) s = ":1:text\ntext\n\n:20:text\n\n:21:text\ntext\ntext\n\n:22: \n\n:25:aa\naa\naaaaa" print([[x.group(1)] + re.findall(r".+\n*", x.group(2)) for x in p.finditer(s)]) 使用您的正则表达式
  • 查找字符串中的所有匹配项
  • p.finditer(s) - 根据第一组内容创建的列表
  • [x.group(1)] - 从第2组内容中获取单个行(使用尾随换行符,0或更多)
  • re.findall(r".+\n*", x.group(2)) - 将列表合并为1。

结果是

[] + re.findall

另一种方法:将所有子字符串与您的模式匹配,然后使用[['1', 'text\n', 'text\n\n'], ['20', 'text\n\n'], ['21', 'text\n', 'text\n', 'text\n\n'], ['22', ' \n\n'], ['25', 'aa\n', 'aa\n', 'aaaaa']]在以可选换行符结尾的行之间添加re.sub

), (

结果:

[(x, "({})".format(re.sub(r".+(?!\n*$)\n+", r"\g<0>), (", y))) for x, y in p.findall(s)]

请参阅Python 3 demo

下面:

  • [('1', '(text\n), (text\n\n)'), ('20', '(text\n\n)'), ('21', '(text\n), (text\n), (text\n\n)'), ('22', '( \n\n)'), ('25', '(aa\n), (aa\n), (aaaaa)')] - 使用正则表达式以包含捕获组内容的元组列表的形式抓取所有匹配项
  • p.findall(s) - 从第1组内容和第2组内容创建一个元组,使用下面描述的方式(x, "({})".format(re.sub(r".+(?!\n*$)\n+", r"\g<0>), (", y)))进行一点修改
  • re.sub - 匹配换行符以外的1 +个字符的模式,如果它们不在字符串的末尾,则匹配1 +换行符号。如果它们位于字符串的末尾,则不会进行替换(最后避免.+(?!\n*$)\n+)。替换字符串中的, ()将整个匹配重新插入到结果字符串中,并将\g<0>附加到其中。