iTextSharp 在 pdf 文件的单词中插入空格
iTextSharp inserting spaces within words from a pdf file
我正在尝试使用 iTextSharp 从以下 pdf 文件中提取文本:
https://www.treasury.gov/ofac/downloads/sdnlist.pdf
这是代码:
var currentText = PdfTextExtractor.GetTextFromPage(pdfReader, 2, new SimpleTextExtractionStrategy());
if (currentText.Length > 0)
{
var capture = new Capture();
capture.Text = currentText;
// write the results to the DB, if any data was found
_dataService.AddCapture(capture);
}
使用 SimpleTextExtractionStrategy,将结果写入数据库,并在单词中包含无数不需要的空格。第2页的前几行写为:
OFFICE OF FOREIGN ASSETS CONTROL SPECIALLY DESIGNATED NATIONALS & BLOCKED PERSONS February 3, 2017 - 2 - A.A. RASPLET IN; a .k.
a. AL MAZ -AN TEY MSDB; a .k.a . AL MAZ -ANTEY PV O 'AI R DEFENSE'
CO NCERN LEAD SYSTE M S DESIGN BUREAU OAO ' OPEN JO INT -STOCK
COMPANY' IMENI ACADEMIC IAN A.A . RASPLETIN; a.k .a. GO LOVNOYE
SISTEMN OYE KONS TRUKT ORSKOY E BYURO OPEN J OIN T-S TOCK C OMP ANY
OF ALMAZ -AN TEY PVO C ONCERN I MEN I ACADEMICIAN A .A. RASPLE TIN;
a.k. a. JO INT STOCK C OMPANY A LMA Z-AN TEY AI R DEFENSE CON CERN
MA IN SYSTE M DESIGN BUREAU NAMED BY ACADE MICIAN A.A.
例如第 4 行和第 6 行中的单词 "JO INT",以及倒数第二行中的单词 "CON CERN"。这些类型的空间出现在整个结果中。不幸的是,这将使查询文本变得不可能。
有谁知道为什么会这样以及如何解决这个问题吗?
为什么会这样
原因实际上是文本提取策略的一个功能,在您的情况下无法按预期工作。
一些背景知识:您认为 PDF 文件中单词之间的 space 不一定是由于指令 绘制 space 字符,它也可以是指令将文本插入位置稍微向右移动的结果。因此,文本提取策略通常会在找到足够大的 right-shift 字符时添加一个 space 字符。有关此的更多信息(特别是“足够大”的部分),例如this answer.
不过,对于您的文档,正文字体的字体宽度信息太小(如果按原样使用,字符看起来粘在一起,没有任何 space in-between);因此,在每对连续字符之间有小的右移,其中一些移宽到足以被上述机制错误地识别为单词分隔。
如何解决这个问题
由于 PDF 中的单词分隔是由绘制 space 字符的指令创建的,因此您不需要上述功能。因此,解决该问题的最简单方法是使用没有该功能的文本提取策略。
您可以通过复制 SimpleTextExtractionStrategy
的源代码(例如来自 here)并注释掉方法 RenderText
中的一些行来创建这样的策略,如下所示:
public virtual void RenderText(TextRenderInfo renderInfo)
{
[...]
if (hardReturn)
{
//System.out.Println("<< Hard Return >>");
AppendTextChunk('\n');
}
else if (!firstRender)
{
// if (result[result.Length - 1] != ' ' && renderInfo.GetText().Length > 0 && renderInfo.GetText()[0] != ' ')
// { // we only insert a blank space if the trailing character of the previous string wasn't a space, and the leading character of the current string isn't a space
// float spacing = lastEnd.Subtract(start).Length;
// if (spacing > renderInfo.GetSingleSpaceWidth() / 2f)
// {
// AppendTextChunk(' ');
// //System.out.Println("Inserting implied space before '" + renderInfo.GetText() + "'");
// }
// }
}
else
{
//System.out.Println("Displaying first string of content '" + text + "' :: x1 = " + x1);
}
[...]
}
使用这种简化的提取策略,可以正确提取您的文本。
我正在尝试使用 iTextSharp 从以下 pdf 文件中提取文本:
https://www.treasury.gov/ofac/downloads/sdnlist.pdf
这是代码:
var currentText = PdfTextExtractor.GetTextFromPage(pdfReader, 2, new SimpleTextExtractionStrategy());
if (currentText.Length > 0)
{
var capture = new Capture();
capture.Text = currentText;
// write the results to the DB, if any data was found
_dataService.AddCapture(capture);
}
使用 SimpleTextExtractionStrategy,将结果写入数据库,并在单词中包含无数不需要的空格。第2页的前几行写为:
OFFICE OF FOREIGN ASSETS CONTROL SPECIALLY DESIGNATED NATIONALS & BLOCKED PERSONS February 3, 2017 - 2 - A.A. RASPLET IN; a .k. a. AL MAZ -AN TEY MSDB; a .k.a . AL MAZ -ANTEY PV O 'AI R DEFENSE' CO NCERN LEAD SYSTE M S DESIGN BUREAU OAO ' OPEN JO INT -STOCK COMPANY' IMENI ACADEMIC IAN A.A . RASPLETIN; a.k .a. GO LOVNOYE SISTEMN OYE KONS TRUKT ORSKOY E BYURO OPEN J OIN T-S TOCK C OMP ANY OF ALMAZ -AN TEY PVO C ONCERN I MEN I ACADEMICIAN A .A. RASPLE TIN; a.k. a. JO INT STOCK C OMPANY A LMA Z-AN TEY AI R DEFENSE CON CERN MA IN SYSTE M DESIGN BUREAU NAMED BY ACADE MICIAN A.A.
例如第 4 行和第 6 行中的单词 "JO INT",以及倒数第二行中的单词 "CON CERN"。这些类型的空间出现在整个结果中。不幸的是,这将使查询文本变得不可能。
有谁知道为什么会这样以及如何解决这个问题吗?
为什么会这样
原因实际上是文本提取策略的一个功能,在您的情况下无法按预期工作。
一些背景知识:您认为 PDF 文件中单词之间的 space 不一定是由于指令 绘制 space 字符,它也可以是指令将文本插入位置稍微向右移动的结果。因此,文本提取策略通常会在找到足够大的 right-shift 字符时添加一个 space 字符。有关此的更多信息(特别是“足够大”的部分),例如this answer.
不过,对于您的文档,正文字体的字体宽度信息太小(如果按原样使用,字符看起来粘在一起,没有任何 space in-between);因此,在每对连续字符之间有小的右移,其中一些移宽到足以被上述机制错误地识别为单词分隔。
如何解决这个问题
由于 PDF 中的单词分隔是由绘制 space 字符的指令创建的,因此您不需要上述功能。因此,解决该问题的最简单方法是使用没有该功能的文本提取策略。
您可以通过复制 SimpleTextExtractionStrategy
的源代码(例如来自 here)并注释掉方法 RenderText
中的一些行来创建这样的策略,如下所示:
public virtual void RenderText(TextRenderInfo renderInfo)
{
[...]
if (hardReturn)
{
//System.out.Println("<< Hard Return >>");
AppendTextChunk('\n');
}
else if (!firstRender)
{
// if (result[result.Length - 1] != ' ' && renderInfo.GetText().Length > 0 && renderInfo.GetText()[0] != ' ')
// { // we only insert a blank space if the trailing character of the previous string wasn't a space, and the leading character of the current string isn't a space
// float spacing = lastEnd.Subtract(start).Length;
// if (spacing > renderInfo.GetSingleSpaceWidth() / 2f)
// {
// AppendTextChunk(' ');
// //System.out.Println("Inserting implied space before '" + renderInfo.GetText() + "'");
// }
// }
}
else
{
//System.out.Println("Displaying first string of content '" + text + "' :: x1 = " + x1);
}
[...]
}
使用这种简化的提取策略,可以正确提取您的文本。