Python - 每行提取可变数量的正则表达式匹配

时间:2017-03-23 01:53:06

标签: python regex

我试图挑出某些正则表达式匹配并将它们作为字符串打印在不同的文件中。

我有这样的输入行:

Example one A;B;C;D;E
Example two FF;EE;WW;DFG;E;J
Example three C;UFT;B;VB

我想要这样的输出:

Example one 1:A 2:B 3:C 4:D 5:E
Example two 1:FF 2:EE 3:WW 4:DFG 5:E 6:J
etc

我正在寻找的元素只是大写字母,单独分隔,没有空格,行结尾\n,元素范围从至少一个到多个,它们可以由一个字母组成或者多个

我已经创造了像这样的输出

def read_file(file_name):
    with open(file_name, "r", encoding="utf-8") as pro_file:
        for line in pro_file:
                matches = re.findall('([A-Z]+[;,\n])', line, re.DOTALL)
                counter = len(matches)
                for element in matches:
                    new_matches = re.findall('[A-Z]+', element, re.DOTALL)
                    print(new_matches)

这给了我所有的上限。将整个文件中的元素单独作为单项列表。我觉得我已经离开了这个轨道......我如何处理到目前为止所取得的成果?还是有更清洁,更简单的方法?我想也许我可以通过counter变量提供的数字以某种方式切片输出?

到目前为止的输出:

['A']
['B']
['C']
etc

1 个答案:

答案 0 :(得分:0)

让我们看一下你现有代码的作用,以输入的第一行为例。

for line in pro_file:

line'Example one A;B;C;D;E\n'

    matches = re.findall('([A-Z]+[;,\n])', line, re.DOTALL)

现在matches['A;', 'B;', 'C;', 'D;', 'E\n']

    counter = len(matches)

counter设置为5

    for element in matches:

以第一个元素为例,将element设置为'A;'

        new_matches = re.findall('[A-Z]+', element, re.DOTALL)

现在new_matches'A;'中所有大写字母的迭代器。有一个这样的运行。你明白为什么new_matches 总是只是一个元素的列表?

您可能应该做的是,而不是迭代matches并单独处理每个元素,对matches的每个元素应用转换,您可以使用生成器表达式执行转换。继续上面的示例,我们matches['A;', 'B;', 'C;', 'D;', 'E\n']。对于每个element,您可以使用

提取仅为大写字母的部分
re.match('[A-Z]+', element).group()

您可以使用enumerate()获取(数字,匹配)元组的迭代器。

enumerate(re.match('[A-Z]+', element.group() for element in matches))

仔细研究一下这一点,以确保您理解。它遍历element中的每个matches,每个{1}}提取前导大写字母,并将每个字母与数字对。 (它是一个生成器,所以如果你尝试打印它,你需要先将它转换成一个列表或其他东西,否则你将得到非特别有用的输出。)

然后,对于每个元组,您可以使用

将其转换为字符串
('{}:{}'.format(number + 1, letters) for number, letters in enumerate(...))

最后,使用' '.join()将所有这些与空格连接起来。把它们放在一起,

' '.join(
    '{}:{}'.format(number + 1, letters) for number, letters in
    enumerate(re.match('[A-Z]+', element.group() for element in matches))
)

然后你将不得不重新连接该行的第一部分。

更好的方法

这或多或少是修复现有代码的最小方法。但实际上,我只是使用split()(或rsplit()从右边开始工作):首先你在空格上划线,然后取最后一个组件并在分号上打破它。

words = line.rsplit(maxsplit=1)
words[0] + ' ' + ' '.join(
    '{}:{}'.format(n + 1, l) for n, l in enumerate(words[-1].split(';'))
)