我正在使用Python解析一些PDF。这些PDF在视觉上组织成行和列。 pdftohtml脚本将这些PDF转换为XML格式,其中包含没有任何层次结构的松散<text>
标记。然后,我的代码需要将这些<text>
标记排序回行。
由于每个<text>
标记都有“top”或“left”坐标等属性,因此我编写了代码,将具有相同“top”坐标的<text>
项追加到列表中。这个清单实际上是一行。
我的代码首先遍历页面,找到所有唯一的“顶部”值,然后将它们附加到顶部列表。然后它迭代这个tops列表。对于每个唯一的最高值,它会搜索具有“最高”值的所有项目,并将它们添加到行列表中。
for side in page:
tops = list( set( [ d['top'] for d in side ] ) )
tops.sort()
for top in tops:
row = []
for blob in side:
if int(blob['top']) == int(top):
row.append(blob)
rows.append(row)
此代码适用于我正在解析的大多数PDF。但是有些情况下,同一行中的项目略微不同的顶部值,关闭一两个。
我正在尝试使我的代码变得有点模糊。
底部的比较似乎很容易解决。像这样:
for blob in side:
rangeLower = int(top) - 2
rangeUpper = int(top) + 2
thisTop = int(blob['top'])
if rangeLower <= thisTop <= rangeUpper :
row.append(blob)
但我首先创建的唯一顶级值列表是个问题。我使用的代码是
tops = list( set( [ d['top'] for d in side ] ) )
在这些边缘情况下,我最终得到了一个列表:
[925, 946, 966, 995, 996, 1015, 1035]
我如何调整该代码以避免列表中包含“995”和“996”?我想确保当整数在1或2之间时,我只得到一个值。
答案 0 :(得分:3)
reduce
根据以前的值过滤值代码:
>>> tops = [925, 946, 966, 995, 996, 1015, 1035]
>>> threshold = 2
>>> reduce(lambda x, y: x + [y] if len(x) == 0 or y > x[-1] + threshold else x, sorted(tops), [])
[925, 946, 966, 995, 1015, 1035]
有几个连续的值:
>>> tops = range(10)
>>> reduce(lambda x, y: x + [y] if len(x) == 0 or y > x[-1] + threshold else x, sorted(tops), [])
[0, 3, 6, 9]
阅读减少可能有点麻烦,所以这里有一个更简单的方法:
res = []
for item in sorted(tops):
if len(res) == 0 or item > res[-1] + threshold:
res.append(item)
答案 1 :(得分:0)
@ njzk2的答案也有效,但这个功能实际上显示了正在发生的事情并且更容易理解:
>>> def sort(list):
... list.sort() #sorts in ascending order
... x = range(0, len(list), 1) #gets range
... x.reverse() #reverses
... for k in x:
... if list[k]-1 == list[k-1]: #if the list value -1 is equal to the next,
... del(list[k-1]) #remove it
... return list #return
...
>>> tops = [925, 946, 966, 995, 996, 1015, 1035]
>>> sort(tops)
[925, 946, 966, 996, 1015, 1035]
>>>