在文档中查找所有空行,并弹出其后的第一行?

1 投票
5 回答
1519 浏览
提问于 2025-04-17 19:09

我想做的事情是逐行查看一个文档,找到每一个空行,然后继续往下看,直到遇到下一行有内容的文字,并把那一行去掉。
举个例子,我想做的事情是这样的:

第一段
这是一行。
这又是一行。

这是一个空行后面的内容,我想把它去掉!
这是我想保留的下一行。

这是我想去掉的另一行。

所以,它会检查每一个空行,直到找到下一句有内容的文字,然后只去掉那一句,之后继续往下看。我在想我应该用 re.split('\n') 来处理这个,但我不太确定。
抱歉我没有代码可以分享,因为我真的不知道从哪里开始。
任何帮助都非常感谢,谢谢!
这段代码是一个更大程序的一部分,我已经花了好几天在上面,直到现在我才弄明白这些,所以我已经完成了大部分的工作。

5 个回答

1

我猜发帖的人(OP)是想直接在文件里删除那些行,也就是说要把它们从文件中去掉。这里有一个改进的解决方案(我之前的方案不太对。感谢J.F Sebastian的指正。)

import fileinput

def remove_line_after_blank(filename, in_place_edit=False):
    previous_line = ''
    for line in fileinput.input(filename, inplace=in_place_edit):
        if not (previous_line == '\n' and line != '\n'):
            print line.rstrip()
        previous_line = line

if __name__ == '__main__':
    remove_line_after_blank('data.txt', in_place_edit=True)

讨论

  • 如果你不想修改原始数据文件,可以去掉 , in_place_edit=True 这部分。
1

如果你用 for line in filehandle: 这样的写法,它会逐行读取文件中的内容。如果你有一个标志,当上一行是空白的时候这个标志会变成真,那么你可以跳过下一行,然后再把这个标志重置回去。

1

对于初学者来说,最简单的方法可能就是Steve提到的:逐行遍历,并用一个标记来记录上一行是否是空行。

但是如果你想要一个更高级的解决方案,就需要从更高的层面重新思考这个问题。你实际上想要的是每个段落的第一行,但不包括第一个段落,而“段落”是由空行分隔开的,对吧?

那么,你该怎么做呢?其实,你可以像用 '\n' 一样,直接用 '\n\n' 来分割文本。所以:

paragraphs = document.split('\n\n')
first_lines = [paragraph.partition('\n')[0] for paragraph in paragraphs]
popped_lines = first_lines[1:]

(我在这里用 partition 而不是 split,因为它只在第一个 '\n' 处分割,其他的保持不变,而且它也能正确处理单行段落——而 paragraph.split('\n', 1) 就做不到这一点。)

不过,你并不想要被分割掉的行的列表,而是想要除了被分割掉的行以外的所有内容,对吧?

paragraphs = document.split('\n\n')
first, rest = paragraphs[0], paragraphs[1:]
rest_edited = [paragraph.partition('\n')[1] for paragraph in rest]

如果你想把这些内容再变回文档:

all_edited = [first] + rest_edited
document_edited = '\n\n'.join(all_edited)

你可以通过使用切片赋值来稍微简化一下,虽然我不确定这样是否更易读:

paragraphs = document.split('\n\n')
paragraphs[1:] = [paragraph.partition('\n')[1] for paragraph in paragraphs[1:]]
document_edited = '\n\n'.join(paragraphs)

正如J.F. Sebastian指出的,问题有点模糊。“空行”是指“没有内容的行”,还是“只有空格的行”?如果是后者,事情就复杂一些,最简单的解决方案可能就是用一个简单的正则表达式(r'\n\s*\n')来分割段落。


同时,如果你处理的是一系列的行(注意,文件就是一系列的行!),而不是一大串字符串,你可以用几种不同的方法来做到这一点,而根本不需要分割。

例如,段落是由非空行组成的,对吧?所以你可以使用 groupby 函数来获取它们:

groups = itertools.groupby(lines, bool)

或者,如果“空”不等于“没有内容”:

groups = itertools.groupby(lines, lambda line: not line.strip())

注意,这样会给你 (False, <行的序列>) 作为每个段落的结果,以及 (True, <空行的序列>) 作为每个空行的结果。如果你想保留空行,可以,但如果你只想把每一组空行替换成一行空行(如果“空”确实意味着“没有内容”),那么丢掉空段落可能更简单:

paragraphs = (group for (key, group) in paragraphs if not key)

然后你可以从除了第一个组之外的所有组中移除第一个元素,最后把这些组重新连接成一个大的序列:

first = next(paragraphs)
edited_paragraphs = (itertools.islice(paragraph, 1) for paragraph in paragraphs)
edited_document = itertools.chain(first, *edited_paragraphs)

最后,如果你有多行空行连续出现的情况呢?首先,你得决定怎么处理它们。如果有两行空行,你要删除第二行吗?如果要,接下来段落的第一行要删除吗(因为它原本是在空行后面),还是不删除(因为它后面的空行已经被删除了)?如果有三行呢?用 '\n\n' 分割会有一种效果,用 '\n\s*\n' 分割又会有另一种效果,而 groupby 则会有不同的效果……但在你知道自己想要什么之前,当然无法说哪种是“正确的”,或者如何“修正”其他的。

撰写回答