Python3.4基于单个字符串捕获文本块

2024-04-27 00:42:12 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经搜索了很多地方,我希望有人能给我指出我错过的链接,或者用这个逻辑帮助我。你知道吗

我们有一个脚本,它从各种设备收集日志,并将它们放在文本文件中。在这些文本文件中有一个时间戳,我们需要收集这个时间戳前后的几行文本。你知道吗

我已经有了一个脚本,可以匹配时间戳并删除某些报告(包括下面)的时间戳,但我无法找出如何匹配时间戳,然后捕获周围的行。你知道吗

regex_time_stamp = re.compile('\d{2}:\d{2}:\d{2}|\d{1,2}y\d{1,2}w\d{1,2}d|\d{1,2}w\d{1,2}d|\d{1,2}d\d{1,2}h')
with open(filename, 'r') as f:
            h = f.readlines()
            for line in h:
                if regex_time_stamp.search(line) is not None:
                    new_line = re.sub(regex_time_stamp, '', line)
                    pre_list.append(new_line)
                else:
                    pre_list.append(line)

如有任何帮助,我们将不胜感激!谢谢你花时间读这篇文章。你知道吗


Tags: re脚本newtime链接stamp地方line
2条回答

基本算法是记住最近读到的三行。当您匹配一个标题时,请阅读下面的两行,并将其与标题和您保存的最后三行合并。你知道吗

或者,由于您正在保存列表中的所有行,只需跟踪哪个元素是当前元素,当您找到一个标题时,就可以返回并获取前两个和后两个元素。你知道吗

用重复行捕获

同意@Bryan Oakley和@TigerhawkT3的基本算法,但是有一个问题:

如果几行连续匹配呢?

您可以通过打印第一个匹配的最后两行,然后打印第二个匹配的最后两行来复制“上下文”行。。。它实际上还包含前面匹配的行。你知道吗

解决方案是跟踪最后打印的行号,以便在当前匹配行之前打印足够的行。你知道吗

灵活的上下文参数

如果你还想前后打印3行而不是2行呢?然后你需要跟踪更多的线路。你知道吗

如果你只想要一个呢?你知道吗

然后,要打印的行数需要是一个参数,算法需要使用它。你知道吗

样本输入和输出

为了清晰起见,这里有一个文件示例,它包含单词MATCH而不是时间戳。其他行包含NOT+行号
== NOT 0 NOT 1 NOT 2 NOT 3 NOT 4 MATCH LINE 5 NOT 6 NOT 7 NOT 8 NOT 9 MATCH LINE 10 MATCH LINE 11 NOT 12 MATCH LINE 13 NOT 14 ==

输出应为:
== NOT 3 NOT 4 LINE 5 NOT 6 NOT 8 NOT 9 LINE 10 LINE 11 NOT 12 LINE 13 NOT 14 ==

解决方案

此解决方案迭代文件并跟踪:

  • 打印的最后一行是什么?如果匹配的行是按顺序出现的,这将注意不复制“上下文”行。你知道吗
  • 匹配的最后一行是什么?这将告诉程序打印当前行,如果它“接近”最后匹配的行。有多近?这由“要打印的行数”参数决定。然后我们还将最后一行打印的变量设置为当前行索引。你知道吗

下面是一个简化的英文算法:

  • 匹配线条时,我们将:
    • 打印最后N行,从最后一行到当前索引
    • 剥离时间戳后打印当前行
    • 设置最后一行\u打印=最后一行\u匹配=当前行索引
    • 继续
  • 当不匹配线时,我们将:
    • 如果当前索引<;最后一行匹配索引+要打印的行数,则打印当前行
  • 当然,我们通过检查限制来确定是否接近文件的开头

不打印但返回数组

此解决方案不直接打印,而是返回一个包含所有要打印行的数组。那只是有点古典。你知道吗

我喜欢给我的“return”变量命名result,但那只是我自己。在整个算法中,结果变量是什么,这一点是显而易见的。你知道吗

代码

您可以使用上面的输入尝试此代码,它将打印相同的输出。你知道吗

def search_timestamps_context(filename, number_of_lines_to_print=2):
    import re
    result = []
    regex_time_stamp = re.compile('\d{2}:\d{2}:\d{2}|\d{1,2}y\d{1,2}w\d{1,2}d|\d{1,2}w\d{1,2}d|\d{1,2}d\d{1,2}h')
    # for my test
    regex_time_stamp = re.compile('MATCH')
    with open(filename, 'r') as f:
                h = f.readlines()
                # Remember which is the last line printed and matched
                last_line_printed = -1
                last_line_matched = -1
                for idx, line in enumerate(h):
                    if regex_time_stamp.search(line) is not None:
                        # We want to print the last "number_of_lines_to_print" lines
                        # ...unless they were already printed
                        # We want to return last lines from idx - number_of_lines_to_print 
                        # print ('** Matched ', line, idx, last_line_matched, last_line_printed)
                        if last_line_printed == -1:
                            lines_to_print = max(idx - number_of_lines_to_print, 0)
                        else: 
                            # Unless we've already printed those lines because of a previous match, then we continue
                            lines_to_print = max(idx - number_of_lines_to_print, last_line_printed + 1)
                        for l in h[lines_to_print:idx]:
                            result.append(l)
                        # Now print the stripped line
                        new_line = re.sub(regex_time_stamp, '', line)
                        result.append(new_line)
                        # Update the last line printed 
                        last_line_printed = last_line_matched = idx

                    else:
                        # If not a match, we still need to print the current line if we had a match N lines before
                        if last_line_matched != -1 and idx < last_line_matched + number_of_lines_to_print:
                            result.append(line)
                            last_line_printed = idx
    return result

filename = 'test_match.txt'
lines = search_timestamps_context(filename, number_of_lines_to_print=2)
print (''.join(lines))

改进

getlines()的使用效率很低:我们在开始之前读取整个文件。你知道吗

只进行迭代会更有效,但是我们需要记住最后一行,以防需要打印它们。为此,我们将保留最后N行的列表,而不是更多。你知道吗

这是留给读者的练习:)

相关问题 更多 >