PDF数据提取------2.相关类介绍
1.简介
构造数据类型PdfString封装Rect类,PdfAnalyzer类中定义一些PDF解析方法。
2.PdfString类与Rect类
public class PdfString : IComparable<PdfString> { public string Words { get; set; } public Rect Position { get; set; } public int PageNumber { get; set; } public PdfString(string str, Rect pos, int pageNum) { this.Words = str; this.Position = pos; this.PageNumber = pageNum; } public override string ToString() { return this.Words; } public static PdfStringComparer GetComparer() { return new PdfString.PdfStringComparer(); } public int CompareTo(PdfString rhs) { return this.Position.x2.CompareTo(rhs.Position.x2); } /// <summary> ///comparer by Horizontal or vertical /// </summary> /// <param name="rhs"></param> /// <param name="which">comparer type</param> /// <returns></returns> public int CompareTo(PdfString rhs, PdfString.PdfStringComparer.ComparisonType which) { switch (which) { case PdfStringComparer.ComparisonType.Horizontal: return this.Position.x2.CompareTo(rhs.Position.x2); case PdfStringComparer.ComparisonType.Vertical: return this.Position.y2.CompareTo(rhs.Position.y2); } return 0; } /// <summary> /// for comparer custom comparer type /// </summary> public class PdfStringComparer : IComparer<PdfString> { private PdfString.PdfStringComparer.ComparisonType whichComparison; public enum ComparisonType { Horizontal, Vertical }; public int Compare(PdfString lhs, PdfString rhs) { return lhs.CompareTo(rhs, whichComparison); } public PdfString.PdfStringComparer.ComparisonType WhichComparison { get { return whichComparison; } set { whichComparison = value; } } } }
public class Rect { public Rect(); public Rect(Obj rect); public Rect(double x1, double y1, double x2, double y2); public double x1 { get; set; } public double x2 { get; set; } public double y1 { get; set; } public double y2 { get; set; } public void __dtor(); public void Attach(Obj obj); public bool Contains(double x, double y); public void Get(ref double out_x1, ref double out_y1, ref double out_x2, ref double out_y2); public double Height(); public void Inflate(double amount); public void Inflate(double x, double y); public bool IntersectRect(Rect rect1, Rect rect2); public void Normalize(); public static Rect op_Assign(Rect lr, Rect rr); public void Set(Rect p); public void Set(double x1, double y1, double x2, double y2); public bool Update(); public bool Update(Obj obj); public double Width(); }
3.关于PdfString类
1.封装Rect原因
a.Rect这个类粒度太小,必须有个类能够保存搜索到关键信息的数据结构,为了根据语义二次识别出准备关键信息。
b. Words属性保存每个搜索结果值
c.Rect:保存结果左上角坐标(x1,y1)右下角坐标(x2,y2)信息
d.PageNumber:数据所在页码,由于PDF中坐标相对于每一页来说的,所以需要页码定位数据为止。
2.实现IComparable<PdfString>接口和加入一个嵌入类PdfStringComparer
a.因为在根据坐标解析PDF中获取数据信息并不是有序,就是说抓取数据并不是按照一定规律保存的,而是杂乱无章的。
b.如果单纯实现IComparable<T>接口可以根据Position属性选择一种方式来讲得到结果集排序,注意实现IComparable<T>
只能选择一种固定排序方式,无法根据情况自定义排序方式,于是PdfString类中引入一个嵌入类PdfStringComparer当使用
x1或x2坐标作为基准则按Horizontal位置坐标排序结果集,反之按照Vertical。
4.关于PdfAnalyzer类
public enum PositionRect { X1, Y1, X2, Y2 } public class PdfAnalyzer { public List<PdfString> RegexSearchAllPages(PDFDoc doc, string pattern) { return RegexSearch(doc, pattern, false, -1, -1, true); } public List<PdfString> RegexSearchByPageRange(PDFDoc doc, string pattern, int startPage, int endPage) { if (endPage > doc.GetPageCount()) throw new Exception("endPage out of MaxRange of pdf."); if (startPage < 1) throw new Exception("startPage out of MixRange of pdf."); if (startPage > endPage) throw new Exception("pageRange is invalid."); return RegexSearch(doc, pattern, false, startPage, endPage, true); } public List<PdfString> RegexSearchByPage(PDFDoc doc, string pattern, int pageIndex) { if (pageIndex > doc.GetPageCount()) throw new Exception("pageIndex out of MaxRange of pdf."); if (pageIndex < 1) throw new Exception("pageIndex out of MixRange of pdf."); return RegexSearch(doc, pattern, false, pageIndex, pageIndex, true); } public List<PdfString> RegexSearch(PDFDoc doc, string pattern, bool ifWholeWord, int startPage, int endPage, bool ignoreCase) { List<PdfString> result = new List<PdfString>(); Int32 page_num = 0; string result_str = ""; string ambient_string = ""; Highlights hlts = new Highlights(); Int32 mode = (Int32)(TextSearch.SearchMode.e_reg_expression | TextSearch.SearchMode.e_highlight); if (ifWholeWord) mode |= (Int32)TextSearch.SearchMode.e_whole_word; if (ignoreCase) mode |= (Int32)TextSearch.SearchMode.e_case_sensitive; int pageCount = doc.GetPageCount(); if (endPage > pageCount) endPage = pageCount; TextSearch txt_search = new TextSearch(); txt_search.Begin(doc, pattern, mode, startPage, endPage); while (true) { TextSearch.ResultCode code = txt_search.Run(ref page_num, ref result_str, ref ambient_string, hlts); if (code == TextSearch.ResultCode.e_found) { hlts.Begin(doc); double[] box = null; string temp = result_str; while (hlts.HasNext()) { box = hlts.GetCurrentQuads(); if (box.Length != 8) { hlts.Next(); continue; } result.Add(new PdfString(result_str, new Rect(box[0], box[1], box[4], box[5]), page_num)); hlts.Next(); } } else if (code == TextSearch.ResultCode.e_done) { break; } } return result; } public List<PdfString> RegexExtractByPositionWithPage(PDFDoc doc, string pattern, int pageIndex, Rect rect, PositionRect positionRect = PositionRect.Y2, double range = 2.0) { return GetNearbyPdfString(RegexSearchByPage(doc, pattern, pageIndex), rect, positionRect, range); } public List<PdfString> GetNearbyPdfString(List<PdfString> pdfStringAll, Rect rect, PositionRect positionRect, double range) { List<PdfString> pdfStringFilter = new List<PdfString>(); foreach (var pdf in pdfStringAll) { if (pdf == null) continue; if (GetRange(pdf.Position, rect, positionRect) > range) continue; pdfStringFilter.Add(pdf); } PdfString.PdfStringComparer comparerType = PdfString.GetComparer(); if (positionRect.Equals(PositionRect.Y2) || positionRect.Equals(PositionRect.Y1)) comparerType.WhichComparison = PdfString.PdfStringComparer.ComparisonType.Horizontal; else if (positionRect.Equals(PositionRect.X1) || positionRect.Equals(PositionRect.X2)) comparerType.WhichComparison = PdfString.PdfStringComparer.ComparisonType.Vertical; pdfStringFilter.Sort(comparerType); return pdfStringFilter; } private double GetRange(Rect pdf, Rect title, PositionRect positionRect) { switch (positionRect) { case PositionRect.X1: return Math.Abs(pdf.x1 - title.x1); case PositionRect.X2: return Math.Abs(pdf.x2 - title.x2); case PositionRect.Y1: return Math.Abs(pdf.y1 - title.y1); case PositionRect.Y2: return Math.Abs(pdf.y2 - title.y2); default: throw new Exception("calculation range of pdfstring with title error."); } } public List<PdfString> RegexExtractByPositionWithAllPage(PDFDoc doc, string pattern, Rect rect, PositionRect positionRect = PositionRect.Y2, double range = 2.0) { return GetNearbyPdfString(RegexSearchAllPages(doc, pattern), rect, positionRect, range); } public List<PdfString> RegexExtractByPositionWithRangePage(PDFDoc doc, string pattern, int startPage, int endPage, Rect rect, PositionRect positionRect = PositionRect.Y2, double range = 2.0) { return GetNearbyPdfString(RegexSearchByPageRange(doc, pattern, startPage, endPage), rect, positionRect, range); } }
注释:
1.RegexSearchAllPages、RegexSearchByPageRange、RegexSearchByPage由方法名可知通过正则表达式得到搜索的 PdfString结果集合。
2.RegexExtractByPositionWithPage、RegexExtractByPositionWithAllPage、RegexExtractByPositionWithRangePage由方法名只知根据传入坐标和误差范围或者每一行或者每列的排序后数据集合。