为什么所有金额数值都是负数?
Why are all the amounts values negative?

原始链接: https://bankstatementconverter.com/blog/posts/2026-08-02-why-are-all-amounts-negative/

有客户反馈称,他们转换后的 PDF 对账单显示所有金额均为负数。经调查发现,该 PDF 使用了尾随负号格式。对于正值,文档中也包含了一个负号,但将其颜色设置为与背景相同,从而使其对肉眼不可见,却能被提取软件检测到。 PDF 创建者很可能使用这种“不可见”字符,是为了在不计算负号宽度的情况下,保持正数右对齐的间距一致性。 为解决此问题,我考虑了两种方案: 1. **OCR**:将页面转换为图片并通过 OCR 处理。虽然有效,但速度较慢且容易出现字符识别错误。 2. **颜色过滤**:识别并忽略非黑色的文本元素。由于我目前的转换器不跟踪文本颜色,因此需要更新代码以捕获颜色属性。 我计划采用颜色过滤方案,因为它比 OCR 更准确、高效。

这篇 Hacker News 讨论聚焦于 *bankstatementconverter.com* 创建者所面临的一个技术挑战:如何解析那些通过“不可见”字符来调整布局的 PDF 文件。 问题起因是一家银行在 PDF 对账单中嵌入了隐藏的减号,以确保列对齐。这些减号的颜色与背景色相同,人类读者无法察觉,但它们却存在于文件的原始文本数据中,导致交易解析出现错误。 讨论主要涵盖了以下要点: * **PDF 的复杂性:** 解析 PDF 极其困难,因为这种格式的设计初衷是视觉呈现,而非数据交换。 * **解决方案:** 建议包括使用特定文档的解析规则(基于文本颜色进行过滤),或者使用 OCR(光学字符识别)来提取文档的“视觉真实内容”,而非底层文本层。 * **系统性挫败感:** 参与者探讨了是否应推动银行提供机器可读的数据格式,而非依赖 PDF——PDF 常被视为一种“通过混淆实现的数字版权管理(DRM)”。 原作者证实,他们通过创建针对特定文档的规则解决了该问题,同时也承认针对此类“损坏”的 PDF,通用的解决方案依然难以实现。
相关文章

原文

A few days ago I got this email from a customer. Something about all the amounts coming out as negative. I converted their PDF.

PDF Sample

Converted Sample

The customer was right, all amounts were coming through as negative. Pretty weird. Interestingly the column headers end with minus sign characters. I then opened up the PDF in PDFSnake to see how the text is encoded. Let’s look at how the values “$110.00-” and “$1,527.57” are encoded.

$110.00-

PDFs are made up of a series of commands. Let’s walk through the commands that appear in this segment.

BT: Begin Text. Tells the PDF renderer to enter into text rendering mode and to save the previous graphics state. Only text operators are legal when inside a Begin Text and End Text block.

ET: End Text. Tells the PDF to exit text rendering mode and restore the graphics state to what it was before the BT command.

Tf: Set text font and size.

Td: Move text position.

Tj: Show text.

g: Set grey level for non-stroking operations.

G: Set grey level for stroking operations.

The above PDF commands could be summarise as “Draw the text ($110.00). Set the grey level to 0. Draw the text (-)”

$1,527.57-

We’ve seen all these commands before and the structure is similar. However there is one key difference. The gray level is set to 0.878 when drawing the minus sign character. The gray level of the minus sign is the same gray level as the background colour. This makes the minus sign invisible. The character is there, but it is not visible and that’s why it comes through when my code processes this PDF.

Why did they encode this PDF like that?

I don’t know, but I can have a guess.

They used trailing minus signs in this PDF. Trailing minus signs make right alignment a bit difficult, because they didn’t just want basic right alignment, they wanted right alignment for the number elements ignoring the minus sign. One way you can achieve this is by always leaving space for the minus sign. But how wide is the minus sign? It depends on the font size, maybe it’s hard to predict. So instead they put in an invisible minus sign for postive values.

Great the PDF looks good, but extracting data from it is a pain. They could avoid all this if they used leading minus signs, but for some reason they wanted trailing minus signs. Okay so now we know why this problem is occuring, how can we get this PDF to convert properly. I can see two solutions.

Solution #1 - OCR the PDF

Instead of reading the text elements in the PDF I could convert the PDF into a series of PNG files and then run OCR software on the PNG files. This should work although it has some downsides. OCRing isn’t 100% accurate. It works pretty well but there’s always a chance that characters are incorrectly recognised. OCRing is significantly slower.

Solution #2 - Strip out non-black text

For this statement type only black coloured text is relevant. Text elements that are set to any other colour can be treated as invisible. This should work, however there’s one problem. When extracting text in Bank Statement Converter, I do not store the colour of the text. So I’ll need to add in code to do this. It shouldn’t be too hard though.

联系我们 contact @ memedata.com