如何检测 python-docx 中的空段落
How to detect an empty paragraph in python-docx
给定一个包含段落的文档
d = docx.Document()
p = d.add_paragraph()
我希望以下技术每次都能奏效:
if len(p._element) == 0:
# p is empty
或
if len(p._p) == 0:
# p is empty
(附带问题,那里有什么区别?似乎 p._p is p._element
在我在野外看到的每种情况下。)
如果我在段落中添加样式,检查将不再有效:
>>> p2 = d.add_paragraph(style="Normal")
>>> print(len(p2._element))
1
明确设置 text=None
也无济于事,这不是我所期望的。
那么如何检查段落是否没有内容(特别是文本和图像,虽然越通用越好)?
更新
我搞砸了一点,发现设置样式显然添加了一个 pPr
元素:
>>> p2._element.getchildren()
[<CT_PPr '<w:pPr>' at 0x7fc9a2b64548>]
元素本身为空:
>>> len(p2._element.getchildren()[0])
0
但更重要的是,它不是运行。
所以我的测试现在看起来像这样:
def isempty(par):
return sum(len(run) for run in par._element.xpath('w:r')) == 0
我对底层系统的了解还不够,不知道这是否是一个合理的解决方案,以及有什么注意事项。
更多更新
看来我需要在这里处理一些不同的情况:
def isempty(par):
p = par._p
runs = p.xpath('./w:r[./*[not(self::w:rPr)]]')
others = p.xpath('./*[not(self::w:pPr) and not(self::w:r)] and '
'not(contains(local-name(), "bookmark"))')
return len(runs) + len(others) == 0
这将跳过所有 w:pPr
元素和 运行 仅包含 w:rPr
元素。任何其他元素,除了书签,无论是直接在段落中还是在 运行 中,都会使结果非空。
<w:p>
元素可以有大量子元素中的任何一个,正如您从此处的 XML 架构摘录中看到的那样:http://python-docx.readthedocs.io/en/latest/dev/analysis/schema/ct_p.html(请参阅 CT_P和 EG_PContent 定义)。
特别是,它通常有一个 w:pPr
子项,这是样式设置所在的位置。
所以你的测试对误报不是很可靠(如果为空被认为是阳性)。
我倾向于使用 paragraph.text == ''
,它通过 运行 进行解析。
A 运行 可以是空的(文本),因此仅仅存在 运行 是不够的。实际文本保存在 a:t
(文本)元素中,该元素也可以为空。因此,.text
方法为您避免了所有这些低级别的并发症,并且具有作为 API 的一部分的好处,在未来的版本中更改的可能性要小得多。
给定一个包含段落的文档
d = docx.Document()
p = d.add_paragraph()
我希望以下技术每次都能奏效:
if len(p._element) == 0:
# p is empty
或
if len(p._p) == 0:
# p is empty
(附带问题,那里有什么区别?似乎 p._p is p._element
在我在野外看到的每种情况下。)
如果我在段落中添加样式,检查将不再有效:
>>> p2 = d.add_paragraph(style="Normal")
>>> print(len(p2._element))
1
明确设置 text=None
也无济于事,这不是我所期望的。
那么如何检查段落是否没有内容(特别是文本和图像,虽然越通用越好)?
更新
我搞砸了一点,发现设置样式显然添加了一个 pPr
元素:
>>> p2._element.getchildren()
[<CT_PPr '<w:pPr>' at 0x7fc9a2b64548>]
元素本身为空:
>>> len(p2._element.getchildren()[0])
0
但更重要的是,它不是运行。
所以我的测试现在看起来像这样:
def isempty(par):
return sum(len(run) for run in par._element.xpath('w:r')) == 0
我对底层系统的了解还不够,不知道这是否是一个合理的解决方案,以及有什么注意事项。
更多更新
看来我需要在这里处理一些不同的情况:
def isempty(par):
p = par._p
runs = p.xpath('./w:r[./*[not(self::w:rPr)]]')
others = p.xpath('./*[not(self::w:pPr) and not(self::w:r)] and '
'not(contains(local-name(), "bookmark"))')
return len(runs) + len(others) == 0
这将跳过所有 w:pPr
元素和 运行 仅包含 w:rPr
元素。任何其他元素,除了书签,无论是直接在段落中还是在 运行 中,都会使结果非空。
<w:p>
元素可以有大量子元素中的任何一个,正如您从此处的 XML 架构摘录中看到的那样:http://python-docx.readthedocs.io/en/latest/dev/analysis/schema/ct_p.html(请参阅 CT_P和 EG_PContent 定义)。
特别是,它通常有一个 w:pPr
子项,这是样式设置所在的位置。
所以你的测试对误报不是很可靠(如果为空被认为是阳性)。
我倾向于使用 paragraph.text == ''
,它通过 运行 进行解析。
A 运行 可以是空的(文本),因此仅仅存在 运行 是不够的。实际文本保存在 a:t
(文本)元素中,该元素也可以为空。因此,.text
方法为您避免了所有这些低级别的并发症,并且具有作为 API 的一部分的好处,在未来的版本中更改的可能性要小得多。