【问题标题】:Python Combine For-LoopsPython 组合 For 循环
【发布时间】:2016-07-01 15:28:40
【问题描述】:

我正在使用 python-docx 来操作 word 文档。以下是我目前必须修改普通段落中的文本:

doc = Document('idk.docx')
for paragraph in doc.paragraphs:
    if "oldtext1" in paragraph.text:
        paragraph.replace("oldtext1","Something")
    if "oldtext2" in paragraph.text:
        paragraph.replace("oldtext2","Somethingelse")

如果我想修改表格中的文字,我需要执行以下操作

tables = doc.tables
for table in tables:
    for row in table.rows:
        for cell in row.cells:
            for paragraph in cell.paragraphs:
                if "oldtext1" in paragraph.text:
                    paragraph.replace("oldtext1","Something")
                if "oldtext2" in paragraph.text:
                    paragraph.replace("oldtext2","Somethingelse")

代码工作正常,文本被替换,但问题是我试图替换文档中文本的所有实例,我不想有 2 个单独的循环(1 个用于段落中的普通文本,另一个用于表格中的文字)

有没有一种简单的方法可以组合这些循环,这样我就不必在 2 个不同的循环中使用相同的 if 语句?

【问题讨论】:

  • 你在循环不同的东西,所以我看不出这段代码有什么问题
  • @cricket_007 我同意,但我建议将逐段处理放在一个函数中以避免代码重复
  • @HumphreyTriscuit - 我正要这么说,但这是个人喜好,我不确定两个块是否相同
  • @cricket_007:我目前拥有的代码很好,但会有更多的 if 语句,我不希望它们同时存在于两组循环中,因为它们是相同的跨度>
  • @Bijan cricket 是正确的;你的循环很好。如果您想要更少的 if 语句,那么将该逻辑放在一个函数中并从每个循环中调用它。

标签: python for-loop


【解决方案1】:

我只会使用生成器推导:

from itertools import chain

for paragraph in chain(doc.paragraphs, (paragraph for table in doc.tables for row in table.rows for cell in row.cells for paragraph in cell.paragraphs)):
    paragraph.replace("oldtext1","Something")
    paragraph.replace("oldtext2","Somethingelse")

请注意,您不需要对 paragraph.replace() 进行前瞻检查

【讨论】:

  • 那么这是先遍历所有段落,然后遍历单元格中的所有文本吗?
  • @Bijan 是的,但是如果你切换添加的顺序,它会做相反的事情
  • 注意:使用itertools.chain 并将listcomp 更改为genexpr 将允许您进行惰性迭代,而不是预先创建2 个可能巨大的临时lists。还需要反转循环的顺序。 from itertools import chainfor paragraph in chain(doc.paragraphs, (para for table in doc.tables for row in table.rows for cell in row.cells for para in cell.paragraphs)): 将获得相同的结果(除非早期循环改变了 doc.tables 中的值之一),但在峰值内存较低的情况下更快地产生初始结果。
  • @HumphreyTriscuit:我在上一条评论中对它进行了掩饰,但是您的 listcomp 中的循环顺序倒退了。最左边,而不是最右边,for 应该超过docs.tables,然后是table.rows,等等
  • @ShadowRanger 你是对的,谢谢!修好了。也完全同意使用itertools.chain(),我会将其添加到我的答案中。再次感谢
【解决方案2】:

虽然生成器理解工作正常,但将此任务委托给它自己的函数可能会更简洁。它的可读性要好得多。

# Python 2.X
def get_all_paragraphs(document):
    for paragraph in document.paragraphs:
        yield paragraph

    for table in document.tables:
        for row in table.rows:
            for cell in row.cells:
                for paragraph in cell.paragraphs:
                    yield paragraph

这可以在 Python 3.X 中通过使用 yield from 构造来清除。

# Python 3.X
def get_all_paragraphs(document):
    yield from document.paragraphs

    for table in document.tables:
        for row in table.rows:
            for cell in row.cells:
                yield from cell.paragraphs

但是,我想不出一种方法来绕过“for row in rows...for cell in row...”模式。

用法是:

for paragraph in get_all_paragraphs(doc):
    paragraph.replace("oldtext1","Something")
    paragraph.replace("oldtext2","Somethingelse")

【讨论】:

    猜你喜欢
    • 2017-08-17
    • 2011-07-18
    • 2021-09-15
    • 2020-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多