0

我使用 iText5 for .NET 通过使用以下代码从 PDF 中提取文本。

private void button1_Click(object sender, EventArgs e)
{
  PdfReader reader2 = new PdfReader("Scharfetter1969.pdf");

  int pagen = reader2.NumberOfPages;
  reader2.Close();

  ITextExtractionStrategy its = new iTextSharp.text.pdf.parser.SimpleTextExtractionStrategy();
  for (int i = 1; i < 2; i++)
  {
    textBox1.Text = "";
    PdfReader reader = new PdfReader("Scharfetter1969.pdf");
    String s = PdfTextExtractor.GetTextFromPage(reader, i, its);
    s = Encoding.UTF8.GetString(ASCIIEncoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(s)));
    textBox1.Text = s;
    reader.Close();
  }
}

但我想从研究论文 pdf 中获取书目数据。

这是从此pdf(尾注格式)中提取的数据示例,这是一个链接

%0 Journal Article
%T Repeated temperature modulation epitaxy for p-type doping and light-emitting diode based on ZnO
%A Tsukazaki, A.
%A Ohtomo, A.
%A Onuma, T.
%A Ohtani, M.
%A Makino, T.
%A Sumiya, M.
%A Ohtani, K.
%A Chichibu, S.F.
%A Fuke, S.
%A Segawa, Y.
%J Nature Materials
%V 4
%N 1
%P 42-46
%@ 1476-1122
%D 2004
%I Nature Publishing Group

但请记住,这是书目信息,它在此 pdf 的元数据中不可用。我想访问文章类型 (%O)、标题 (%T)、作者 (%A)、日期 (%D) 和 (%I),并以窗口形式将其显示到不同的指定文本框。

如果有人有任何代码,我正在使用 C#,或者指导我如何做到这一点。

4

1 回答 1

2

PDF 是一种单向格式。您将数据放入其中,以便它在所有设备(显示器、打印机等)上一致呈现,但该格式从未打算将数据拉回。任何和所有这样做的尝试都是纯粹的猜测工作。iText 的PdfTextExtractor作品,但您将不得不根据您自己的任意规则集将内容拼凑在一起,这些规则可能会从 PDF 更改为 PDF。提供的 PDF 是由 InDesign 创建的,它在使文本看起来不错方面做得非常好,实际上它使解析数据变得更加困难。

也就是说,如果您的 PDF 在视觉上都是一致的,您可以尝试在保留格式的同时提取数据并使用格式规则来猜测是什么。那篇文章将为您提供一些您可以猜到的 HTML 格式。(如果这真的有效,我建议返回比 HTML 更具体的内容,但我会留给你。)

对您提供的 PDF 运行它显示标题使用HelveticaNeue-LightExt大约 17pts 的字体,因此您可以编写一个规则来查找使用该大小的所有行并将它们组合在一起。作者HelveticaNeue-Condensed在大约 10 分时完成,所以这是另一条规则。

下面的代码是上面链接的代码的修改版本。它是针对 iTextSharp 5.1.1.0 的完整工作 C# 2010 WinForms 应用程序。它会提取所提供 PDF 的标题和作者,但您需要针对其他 PDF 和元数据对其进行调整。具体实现细节见代码中的注释。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using iTextSharp.text.pdf.parser;
using iTextSharp.text.pdf;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            PdfReader reader = new PdfReader(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "nmat4-42.pdf"));
            TextWithFontExtractionStategy S = new TextWithFontExtractionStategy();
            string F = iTextSharp.text.pdf.parser.PdfTextExtractor.GetTextFromPage(reader, 1, S);

            //Buffers to hold various parts from the PDF
            List<string> titles = new List<string>();
            List<string> authors = new List<string>();

            //Array of lines of text
            string[] lines = F.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);

            //Temporary string
            string t;

            //Loop through each line in the array
            foreach (string line in lines)
            {
                //See if the line looks like a "title"
                if (line.Contains("HelveticaNeue-LightExt") && line.Contains("font-size:17.28003"))
                {
                    //Remove the HTML tags
                    titles.Add(System.Text.RegularExpressions.Regex.Replace(line, "</?span.*?>", "").Trim());
                }
                    //See if the line looks like an "author"
                else if (line.Contains("HelveticaNeue-Condensed") && line.Contains("font-size:9.995972"))
                {
                    //Remove the HTML tags and trim extra characters
                    t = System.Text.RegularExpressions.Regex.Replace(line, "</?span.*?>", "").Trim(new char[] { ' ', ',', '*' });
                    //Make sure we have a valid name, probably need some more exceptions here, too
                    if (!string.IsNullOrWhiteSpace(t) && t != "AND")
                    {
                        authors.Add(t);
                    }
                }
            }
            //Write out the title to the console
            Console.WriteLine("Title  : {0}", string.Join(" ", titles.ToArray()));
            //Write out each author
            foreach (string author in authors)
            {
                Console.WriteLine("Author : {0}", author);
            }
            Console.WriteLine(F);

            this.Close();
        }

        public class TextWithFontExtractionStategy : iTextSharp.text.pdf.parser.ITextExtractionStrategy
        {
            //HTML buffer
            private StringBuilder result = new StringBuilder();

            //Store last used properties
            private Vector lastBaseLine;
            private string lastFont;
            private float lastFontSize;

            //http://api.itextpdf.com/itext/com/itextpdf/text/pdf/parser/TextRenderInfo.html
            private enum TextRenderMode
            {
                FillText = 0,
                StrokeText = 1,
                FillThenStrokeText = 2,
                Invisible = 3,
                FillTextAndAddToPathForClipping = 4,
                StrokeTextAndAddToPathForClipping = 5,
                FillThenStrokeTextAndAddToPathForClipping = 6,
                AddTextToPaddForClipping = 7
            }



            public void RenderText(iTextSharp.text.pdf.parser.TextRenderInfo renderInfo)
            {
                string curFont = renderInfo.GetFont().PostscriptFontName;
                //Check if faux bold is used
                if ((renderInfo.GetTextRenderMode() == (int)TextRenderMode.FillThenStrokeText))
                {
                    curFont += "-Bold";
                }

                //This code assumes that if the baseline changes then we're on a newline
                Vector curBaseline = renderInfo.GetBaseline().GetStartPoint();
                Vector topRight = renderInfo.GetAscentLine().GetEndPoint();
                iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(curBaseline[Vector.I1], curBaseline[Vector.I2], topRight[Vector.I1], topRight[Vector.I2]);
                Single curFontSize = rect.Height;

                //See if something has changed, either the baseline, the font or the font size
                if ((this.lastBaseLine == null) || (curBaseline[Vector.I2] != lastBaseLine[Vector.I2]) || (curFontSize != lastFontSize) || (curFont != lastFont))
                {
                    //if we've put down at least one span tag close it
                    if ((this.lastBaseLine != null))
                    {
                        this.result.AppendLine("</span>");
                    }
                    //If the baseline has changed then insert a line break
                    if ((this.lastBaseLine != null) && curBaseline[Vector.I2] != lastBaseLine[Vector.I2])
                    {
                        this.result.AppendLine("<br />");
                    }
                    //Create an HTML tag with appropriate styles
                    this.result.AppendFormat("<span style=\"font-family:{0};font-size:{1}\">", curFont, curFontSize);
                }

                //Append the current text
                this.result.Append(renderInfo.GetText());

                //Set currently used properties
                this.lastBaseLine = curBaseline;
                this.lastFontSize = curFontSize;
                this.lastFont = curFont;
            }

            public string GetResultantText()
            {
                //If we wrote anything then we'll always have a missing closing tag so close it here
                if (result.Length > 0)
                {
                    result.Append("</span>");
                }
                return result.ToString();
            }

            //Not needed
            public void BeginTextBlock() { }
            public void EndTextBlock() { }
            public void RenderImage(ImageRenderInfo renderInfo) { }
        }
    }
}
于 2011-12-06T15:27:03.363 回答