Text aus Pdf auslesen mit ITextSharp

  • VB.NET

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von petaod.

    Text aus Pdf auslesen mit ITextSharp

    Hi!

    Wir kriegen Rechnungen im Pdf-Format, und wollen die Werte in eine Datenbank transferieren, also Auftragsnummer, Rechnungsposten, Datum, den ganzen Kram.
    Bislang habich mit ITextSharp nur zustande gebracht, den Seiten-Text auszulesen.
    Wäre ja auch brauchbar, nur sind die Rechnungen im Briefkopf mehrspaltig gelayoutet, und die Zeilen der rechten Spalte geraten in ziemlich unvorhersehbarer Weise zwischen die Zeilen der linken Spalte, und solche Scherze.
    Kann man mit ITextSharp iwie Seiten-Bereiche auslesen, oder die X/Y-Positionen, an denen eine Zeile steht, oder Textfelder, oder was auch immer?
    Mein GanzSeiten-Lese-Code sieht bislang so aus:

    VB.NET-Quellcode

    1. Public Shared Function ReadPdf(file As String) As String
    2. ReadPdf = ""
    3. Using pdfReader As New PdfReader(file)
    4. For page As Integer = 1 To pdfReader.NumberOfPages
    5. ReadPdf &= PdfTextExtractor.GetTextFromPage(pdfReader, page)
    6. Next
    7. pdfReader.Close()
    8. End Using
    9. End Function
    Hi @ErfinderDesRades,
    kommentiere mal eben, damit ich nicht vergesse hier zu schreiben. Bin mir ziemlich sicher, dass ein ehemaliger Berufs-Schul-Kamerad so etwas ähnliches als Abschlussprojekt gemacht hat. (Beziehungsweise war das ein Teil davon)
    Ich bringe das mal in Erfahrung und melde mich noch einmal, vielleicht kann er mir etwas zur Verfügung stellen.

    Ich selbst habe leider noch nie mit ITextSharp gearbeitet und mache selten was mit PDFs, das letzte mal, als ich da was versucht habe ist 4 Jahre her.
    Wenn die grauen Zellen noch einigermaßen stimmen gibt es doch Paragraphs und Tables in den PDFs- könnte man vielleicht mit dem Schlagwort 'Tables' finden?

    Wie gesagt,
    melde mich nochmal.

    Drahuverar
    Option Strict On!
    Ich hatte so etwas ähnliches mal mit dem Acrobat SDK gemacht.
    Damit konnte ich das PDF als Excel speichern.

    Elegant ist das nicht und es funktioniert auch nicht für alle PDFs.
    Bei manchen bekommt man kein sinnvolles Excel.
    Dann bleibt nur noch die Variante, die einzelnen Felder auszulesen und halbwegs intelligent zu interpretieren.

    Wenn das mit iTextSharp eleganter geht, muss ich mir das auch mal anschauen.
    Vielleicht kommen wir hier im Thread ja auf brauchbare Lösungsansätze.
    Ich habe die nächsten Wochen nämlich auch wieder so ein PDF-Projekt auf der Liste.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Du kann mit mit iTextSharp die Fields direkt per .Name ansprechen (unabhängig von der Page) und den .Value als String weiterverarbeiten. Bei nicht selbsterstellten PDF besteht das Problem darin das man den .Name nicht kennt. Ich schaue, wenn gewünscht, morgen mal nach denn ich hatte mir mal ein Tool gebastelt um den .Name und den .Value, aus einer PDF, in einer DGV dargestellt. Und einzelne Fields zum ansprechen müssen vorhanden sein und der .Name sollte auch nicht wechseln. ;)
    Also ich habe es nicht finden können. Für mich war das damals auch eher Spielerei als das ich es gebraucht hätte... Ich habe mir aber gerade die mühe gemacht und es aus dem Gedächtnis nachvollzogen. Hab es an meiner eigenen PDF getestet und hat auch wunderbar funktioniert. Ich hoffe das hilft...

    Form:
    - 1x TextBox, Multiline = True, ScrollBars = Vertical, Name = "TB_FieldDataExplicite"
    - 1x Button, Name ="B_browse"

    VB.NET-Quellcode

    1. Public pdfTemplate As String
    2. Public pdfField As Object
    3. Public pdfFieldName As String
    4. Public readerPDF As PdfReader
    5. Private Sub B_browse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles B_browse.Click
    6. With OpenFileDialog1
    7. .DefaultExt = ".PDF"
    8. .DereferenceLinks = True
    9. .Filter = "PDF files (*.PDF)|*.PDF"
    10. .Multiselect = False
    11. .Title = "Select a PDF file to open"
    12. .ValidateNames = True
    13. Me.pdfTemplate = .FileName
    14. End With
    15. readerPDF = New PdfReader(Me.pdfTemplate)
    16. Dim pdfFormField As AcroFields = readerPDF.AcroFields
    17. For Each Me.pdfField In readerPDF.AcroFields.Fields
    18. ' bei ".getField(pdfField.key.ToString), also mit dem gesamten Namen hat es bei mir nicht funktioniert. Ich denke es liegt daran, wie die PDF erzeugt wurde.
    19. pdfFieldName = Microsoft.VisualBasic.Strings.Right(pdfField.key.ToString, Microsoft.VisualBasic.Strings.Len(pdfField.key.ToString) - Microsoft.VisualBasic.Strings.InStrRev(pdfField.key.ToString, "."))
    20. If TB_FieldDataExplicite.Text Is "" Then
    21. TB_FieldDataExplicite.Text = pdfField.key.ToString & Environment.NewLine & "=>" & pdfFormField.GetField(pdfFieldName)
    22. Else
    23. TB_FieldDataExplicite.Text = TB_FieldDataExplicite.Text & Environment.NewLine & _
    24. pdfField.key.ToString & Environment.NewLine & "=>" & pdfFormField.GetField(pdfFieldName)
    25. End If
    26. Next
    27. End Sub


    Eine Rückmeldung würde mich freuen.
    @Icke: Danke für das mit die Felder auslesen, aber meine Dokumente sind ohne Eingabefelder, wie sich dadurch gezeigt hat.

    @Akanel: Die Doku-Site wird bei mir ganz unleserlich dargestellt - sowohl bei Firefox als auch IE
    . .

    Demnächst werd ich dem mit "Read from Position" auf dem Grund gehen, melde mich dann nochmal.

    ErfinderDesRades schrieb:

    meine Dokumente sind ohne Eingabefelder
    Meine auch.
    Ich habe deshalb zunächst gespielt mit iTextSharp.text.pdf.parser.PdfTextExtractor.GetTextFromPage unter Verwendung verschiedener Strategien.
    Ohne durchschlagenden Erfolg. Die getesteten Verfahren sind alle pseudo-intelligent und bringen meine Tabellenstruktur mehr durcheinander als dass sie vereinfachen.

    Die einzige Methode, die bei mir Erfolg brachte war das manuelle Extrahieren der Textfelder aus dem vom PdfReader per GetPageContent aufbereiteten Input.
    Weil ich weiß, wie die Tabelle aussieht, kann ich aus dieser Feldliste dann eine DataTable erzeugen.

    Falls jemand Interesse hat, wie ich die Felder extrahiere, stelle ich den Parser-Code hier mal rein.
    Vielleicht kann's ja jemand als Ausgangspunkt für seine Lösung verwenden:
    PdfParser

    VB.NET-Quellcode

    1. Imports iTextSharp.text.pdf
    2. Imports System.Text
    3. Friend Class PdfParser
    4. Private PdfDocument_ As PdfReader
    5. Private Path As String
    6. Sub New(Path As String)
    7. Me.Path = Path
    8. End Sub
    9. Private ReadOnly Property PdfDocument As PdfReader
    10. Get
    11. If PdfDocument_ Is Nothing Then PdfDocument_ = New PdfReader(Path)
    12. Return PdfDocument_
    13. End Get
    14. End Property
    15. Friend ReadOnly Property Pages As List(Of String)
    16. Get
    17. Dim p As New List(Of String)
    18. For PageNr = 1 To PdfDocument.NumberOfPages
    19. Dim Text = Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, PdfDocument.GetPageContent(PageNr)))
    20. p.Add(Text)
    21. Next
    22. Return p
    23. End Get
    24. End Property
    25. Friend ReadOnly Property PdfFields() As List(Of String)
    26. Get
    27. Dim l As New List(Of String)
    28. For i = 1 To PdfDocument.NumberOfPages
    29. l.AddRange(PdfFields(i))
    30. Next
    31. Return l
    32. End Get
    33. End Property
    34. Friend ReadOnly Property PdfFields(PageNr As Integer) As List(Of String)
    35. Get
    36. Return Fields(Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, PdfDocument.GetPageContent(PageNr))))
    37. End Get
    38. End Property
    39. Private Function Fields(PdfPage As String) As List(Of String)
    40. Dim l As New List(Of String)
    41. For Each f In PdfPage.Split({vbLf}, StringSplitOptions.None)
    42. If f Like "(*)Tj" Then 'a text field
    43. f = f.Substring(1, f.Length - 4) 'extract text
    44. f = f.Replace("\(", "(").Replace("\)", ")") 'unescape brackets
    45. l.Add(f)
    46. End If
    47. Next
    48. Return l
    49. End Function
    50. End Class



    Aufruf:

    VB.NET-Quellcode

    1. Dim PDF As New PdfParser(PdfFile.FullName)
    2. Dim FieldList = PDF.PdfFields

    Falls jemand bessere Vorschläge hat:
    Immer her damit.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „petaod“ ()

    @petaod
    Ich habe mir das mal angesehen. Ist schon recht schnuffig. Habe mir den Teil:

    VB.NET-Quellcode

    1. Dim p As New List(Of String)
    2. For PageNr = 1 To readerPDF.NumberOfPages
    3. Dim Text = Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, readerPDF.GetPageContent(PageNr)))
    4. p.Add(Text)
    5. Next

    raus gepickt und mir das Ergebnis mal angesehen. Sowohl mit "Adobe Livecycle Designer, ALD" erstellte PDF's als auch mit LaTeX erstellte PDF's. Die Texte aus den "PDF.Labels" werden bei beiden in "(" hier der Text ")" Klammern gesetzt und das kann dann extrahiert werden. Jedoch werden auch Bilder, bei LaTeX so "(¥)" in klammer dargestellt. und die Umlaute sehen auch nicht besser aus. Hingegen bei ALD erstellten PDF's werden umlaute => \344 für ö dargestellt. Mich würde interessieren was den Rechnungen von @ErfinderDesRades so raus kommt.

    Icke schrieb:

    Hingegen bei ALD erstellten PDF's werden umlaute => \344 für ö dargestellt.
    Da müsste man wohl, um es universell zu machen den Unescaper, der bei mir lediglich aus f = f.Replace("\(", "(").Replace("\)", ")") besteht, noch etwas erweitern.
    Vielleicht gibt es in iTextSharp auch schon so eine Funktion.

    Der Parser ist momentan noch sehr auf einen einzelnen Anwendungsfall ausgerichtet.
    Inzwischen habe ich ihn erweitert und schaffe es tatsächlich die Tabelle daraus zu erzeugen.

    Ich nutze dazu die PDF Operators und werte sie aus.
    Siehe PDF-Referenz Anhang A (Seite 985)

    Bei meinem PDF habe ich festgestellt, dass als Spaltentrennzeichen die "ET"-Operatoren verwendet werden und als Zeilentrennzeichen die "S"-Operatoren.
    Außerdem nutze ich die Tatsache, dass ich die Spaltenanzahl meiner gewünschten Tabelle kenne.
    Aus dieser Kombination bekomme ich eine DataTable, die exakt meiner gewünschten Tabelle entspricht.

    Hier mal der aktuelle Entwicklungsstand:
    PdfParser

    VB.NET-Quellcode

    1. Imports iTextSharp.text.pdf
    2. Imports System.Text
    3. Friend Class PdfParser
    4. Private PdfDocument_ As PdfReader
    5. Private Path As String
    6. Friend DataTable As New DataTable
    7. 'Friend Property SOHmarker As String
    8. 'Friend Property STXmarker As String
    9. 'Friend Property ETXmarker As String
    10. 'Friend Property EOTmarker As String
    11. Friend Property TABmarker As String ' = "ET"
    12. Friend Property LFmarker As String ' = "S"
    13. 'Friend Property TableSeparator As String
    14. Friend Const NUL = Chr(0)
    15. 'Friend Const SOH = Chr(1)
    16. ' Friend Const STX = Chr(2)
    17. 'Friend Const ETX = Chr(3)
    18. 'Friend Const EOT = Chr(4)
    19. Friend Const TAB = Chr(9) '9
    20. Friend Const LF = Chr(10) '10
    21. Sub New(Path As String)
    22. Me.Path = Path
    23. End Sub
    24. Private ReadOnly Property PdfDocument As PdfReader
    25. Get
    26. If PdfDocument_ Is Nothing Then PdfDocument_ = New PdfReader(Path)
    27. Return PdfDocument_
    28. End Get
    29. End Property
    30. Friend ReadOnly Property Info As Dictionary(Of String, String)
    31. Get
    32. Return PdfDocument.Info
    33. End Get
    34. End Property
    35. Friend ReadOnly Property Pages As List(Of String)
    36. Get
    37. Dim p As New List(Of String)
    38. For PageNr = 1 To PdfDocument.NumberOfPages
    39. Dim Text = Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, PdfDocument.GetPageContent(PageNr)))
    40. p.Add(Text)
    41. Next
    42. Return p
    43. End Get
    44. End Property
    45. Friend ReadOnly Property PdfFields() As List(Of String)
    46. Get
    47. Dim l As New List(Of String)
    48. For i = 1 To PdfDocument.NumberOfPages
    49. l.AddRange(PdfFields(i))
    50. Next
    51. Return l
    52. End Get
    53. End Property
    54. Friend ReadOnly Property PdfFields(PageNr As Integer) As List(Of String)
    55. Get
    56. Return Fields(Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, PdfDocument.GetPageContent(PageNr))))
    57. End Get
    58. End Property
    59. Function CreateDataTable(Optional Columns As Integer = 99) As Boolean
    60. Return CreateDataTable(Columns, Columns)
    61. End Function
    62. Function CreateDataTable(MinColumns As Integer, MaxColumns As Integer) As Boolean
    63. Try
    64. DataTable = New DataTable
    65. For i = 1 To MaxColumns
    66. DataTable.Columns.Add()
    67. Next
    68. Dim PDF = PdfDocument
    69. Dim Cell As String = ""
    70. Dim Row As New List(Of String)
    71. For Each Page In Pages
    72. Dim PageFields = Fields(Page)
    73. For Each Field In PageFields
    74. Debug.Print(Field)
    75. If Field = NUL Then
    76. ElseIf Field = TAB Then
    77. 'If Row.Count < MaxColumns Then Row.Add(Cell.TrimStart(LF))
    78. Row.Add(Cell.TrimStart(LF))
    79. Cell = ""
    80. ElseIf Field = LF Then
    81. If Row.Count >= MinColumns AndAlso Row.Count <= MaxColumns Then DataTable.Rows.Add(Row.ToArray)
    82. Row.Clear()
    83. Else
    84. Cell &= LF & Field
    85. End If
    86. Next
    87. Next
    88. Return True
    89. Catch ex As Exception
    90. ex.Message.Trace("PdfParser", "CreateDataTable") 'die Trace-Extension kann auch durch Debug.Print ersetzt werden
    91. Return False
    92. End Try
    93. End Function
    94. Private Function Fields(TextFromPage As String) As List(Of String)
    95. Dim l As New List(Of String)
    96. For Each f In TextFromPage.Split({vbLf}, StringSplitOptions.None)
    97. If f Like "(*)Tj" Then 'a text field
    98. f = f.Substring(1, f.Length - 4) 'extract text
    99. f = f.Replace("\(", "(").Replace("\)", ")") 'unescape brackets
    100. l.Add(f)
    101. ElseIf f = "" Then
    102. l.Add(NUL)
    103. 'ElseIf f Like SOHmarker Then
    104. ' l.Add(SOH)
    105. 'ElseIf f Like STXmarker Then
    106. ' l.Add(STX)
    107. 'ElseIf f Like ETXmarker Then
    108. ' l.Add(ETX)
    109. 'ElseIf f Like EOTmarker Then
    110. ' l.Add(EOT)
    111. ElseIf f Like TABmarker Then
    112. l.Add(TAB)
    113. ElseIf f Like LFmarker Then
    114. l.Add(LF)
    115. End If
    116. Next
    117. Return l
    118. End Function
    119. End Class

    Aufruf:

    VB.NET-Quellcode

    1. Sub ProcessPdf(PdfFile As FileInfo)
    2. PDF = New PdfParser(PdfFile.FullName)
    3. ''Field Debugging - uncomment this block for structure analysis
    4. 'For Each Field In PDF.PdfFields
    5. ' Debug.Print(Field)
    6. 'Next
    7. PDF.TABmarker = "ET" 'column separator
    8. PDF.LFmarker = "S" 'row separator
    9. If PDF.CreateDataTable(5) Then 'create a five-column DataTable
    10. ProcessDataTable(PDF.DataTable) 'process the DataTable
    11. End If
    12. End Sub

    Meine PDF-Tabelle hat keine Headers und keine Rahmen, sonst könnte man ggf. noch andere Operatoren mit in Betracht ziehen.

    Mit jeder neuen PDF werde ich wohl neue Erkenntnisse finden, aber die Grundfunktionen scheinen schon mal recht zuverlässig zu laufen.
    Wer will, darf sich gerne austoben.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Icke schrieb:

    Mich würde interessieren was den Rechnungen von @ErfinderDesRades so raus kommt.
    Parser.Pages hatte ich bis Dato nicht getestet, weil ich annahm, in der List(of String) steht derselbe Text halt seitenweise drin, den ich eh schon erhalte.
    Aber tatsächlich steht da scheints pdf-Code - Auszug:

    Quellcode

    1. entfernt
    Ob ich da iwelche Positions-Zuordnungen der Text-Teile draus ausfummeln kann, muss ich mal in einer stillen Stunde herauszukriegen versuchen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Bei dir scheinen die Daten nicht als einzelne Textfelder zu kommen, sondern als Array von Strings.
    [(R)-2.5502( )1.98161(E)2.82817( )1.98161(C)-2.5502( )1.98161(H)-2.5502( )1.98161(N)-2.5502( )1.98161(U)-2.5502( )1.98161(N)-2.5502( )1.98161(G)778]TJ
    soll wohl R E C H N U N G heissen.

    Der TJ-Operator meint: Show text, allowing individual glyph positioning
    array TJ Show one or more text strings, allowing individual glyph positioning (see implementation note 58 in Appendix H).
    ach element of array can be a string or a number.
    If the element is a string, this operator shows the string.
    If it is a number, the operator adjusts the text position by that amount; that is, it translates the text matrix, Tm.
    The number is expressed in thousandths of a unit of text space (see Section 5.3.3, “Text Space Details,” and implementation note 59 in Appendix H).
    This amount is subtracted from the current horizontal or vertical coordinate, depending on the writing mode.
    In the default coordinate system, a positive adjustment has the effect of moving the next glyph painted either to the left or down by the given amount.

    Ich werde mal versuchen die TJ-Felder ebenfalls zu parsen.

    Edit:
    PdfParser

    VB.NET-Quellcode

    1. Imports iTextSharp.text.pdf
    2. Imports System.Text
    3. Friend Class PdfParser
    4. Private PdfDocument_ As PdfReader
    5. Private Path As String
    6. Friend DataTable As New DataTable
    7. 'Friend Property SOHmarker As String
    8. 'Friend Property STXmarker As String = "##/##/#### ##:##"
    9. 'Friend Property ETXmarker As String
    10. 'Friend Property EOTmarker As String
    11. Friend Property TABmarker As String ' = "ET"
    12. Friend Property LFmarker As String ' = "S"
    13. 'Friend Property TableSeparator As String
    14. Friend Const NUL = Chr(0)
    15. 'Friend Const SOH = Chr(1)
    16. ' Friend Const STX = Chr(2)
    17. 'Friend Const ETX = Chr(3)
    18. 'Friend Const EOT = Chr(4)
    19. Friend Const TAB = Chr(9) '9
    20. Friend Const LF = Chr(10) '10
    21. Sub New(Path As String)
    22. Me.Path = Path
    23. End Sub
    24. Private ReadOnly Property PdfDocument As PdfReader
    25. Get
    26. If PdfDocument_ Is Nothing Then PdfDocument_ = New PdfReader(Path)
    27. Return PdfDocument_
    28. End Get
    29. End Property
    30. Friend ReadOnly Property Info As Dictionary(Of String, String)
    31. Get
    32. Return PdfDocument.Info
    33. End Get
    34. End Property
    35. Friend ReadOnly Property Pages As List(Of String)
    36. Get
    37. Dim p As New List(Of String)
    38. For PageNr = 1 To PdfDocument.NumberOfPages
    39. Dim Text = Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, PdfDocument.GetPageContent(PageNr)))
    40. p.Add(Text)
    41. Next
    42. Return p
    43. End Get
    44. End Property
    45. Friend ReadOnly Property PdfFields() As List(Of String)
    46. Get
    47. Dim l As New List(Of String)
    48. For i = 1 To PdfDocument.NumberOfPages
    49. l.AddRange(PdfFields(i))
    50. Next
    51. Return l
    52. End Get
    53. End Property
    54. Friend ReadOnly Property PdfFields(PageNr As Integer) As List(Of String)
    55. Get
    56. Return Fields(Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, PdfDocument.GetPageContent(PageNr))))
    57. End Get
    58. End Property
    59. Function CreateDataTable(Optional Columns As Integer = 99) As Boolean
    60. Return CreateDataTable(Columns, Columns)
    61. End Function
    62. Function CreateDataTable(MinColumns As Integer, MaxColumns As Integer) As Boolean
    63. Try
    64. DataTable = New DataTable
    65. For i = 1 To MaxColumns
    66. DataTable.Columns.Add()
    67. Next
    68. Dim PDF = PdfDocument
    69. Dim Cell As String = ""
    70. Dim Row As New List(Of String)
    71. For Each Page In Pages
    72. Dim PageFields = Fields(Page)
    73. For Each Field In PageFields
    74. Debug.Print(Field)
    75. If Field = NUL Then
    76. ElseIf Field = TAB Then
    77. 'If Row.Count < MaxColumns Then Row.Add(Cell.TrimStart(LF))
    78. Row.Add(Cell.TrimStart(LF))
    79. Cell = ""
    80. ElseIf Field = LF Then
    81. If Row.Count >= MinColumns AndAlso Row.Count <= MaxColumns Then DataTable.Rows.Add(Row.ToArray)
    82. Row.Clear()
    83. Else
    84. Cell &= LF & Field
    85. End If
    86. Next
    87. Next
    88. Return True
    89. Catch ex As Exception
    90. ex.Message.Trace("PdfParser", "CreateDataTable")
    91. Return False
    92. End Try
    93. End Function
    94. Function Fields(TextFromPage As String) As List(Of String)
    95. Dim l As New List(Of String)
    96. For Each f In TextFromPage.Split({vbLf}, StringSplitOptions.None)
    97. f = f.TrimEnd(Chr(13))
    98. If f Like "(*)Tj" Then 'a text field
    99. f = UnEscape(f.Substring(1, f.Length - 4)) 'extract text
    100. ' f = f.Replace("\(", "(").Replace("\)", ")") 'unescape brackets
    101. l.Add(f)
    102. ElseIf f Like "*[[]*[]]TJ" Then 'a glyph text array
    103. f = UnEscape(UnGlyphe(f)) 'extract text part of glyphes
    104. l.Add(f)
    105. ElseIf f = "" Then
    106. l.Add(NUL)
    107. 'ElseIf f Like SOHmarker Then
    108. ' l.Add(SOH)
    109. 'ElseIf f Like STXmarker Then
    110. ' l.Add(STX)
    111. 'ElseIf f Like ETXmarker Then
    112. ' l.Add(ETX)
    113. 'ElseIf f Like EOTmarker Then
    114. ' l.Add(EOT)
    115. ElseIf f Like TABmarker Then
    116. l.Add(TAB)
    117. ElseIf f Like LFmarker Then
    118. l.Add(LF)
    119. End If
    120. Next
    121. Return l
    122. End Function
    123. Friend Function UnGlyphe(GlypheString As String) As String
    124. Dim InText = False, InArray = False, InEscape = False, s = ""
    125. For Each c In GlypheString
    126. If c = "["c Then
    127. InArray = True
    128. ElseIf c = "]"c Then
    129. InArray = False
    130. ElseIf InArray Then
    131. If c = "("c AndAlso Not InEscape Then
    132. InText = True
    133. ElseIf c = ")"c AndAlso Not InEscape Then
    134. InText = False
    135. ElseIf InText Then
    136. InEscape = c = "\"c
    137. s &= c
    138. End If
    139. End If
    140. Next
    141. Return s
    142. End Function
    143. Friend Function UnEscape(s As String) As String
    144. Dim o = "", Esc = False, nnn = ""
    145. For Each c In s
    146. If Esc Then
    147. Esc = False
    148. Select Case c
    149. Case "\"c, "("c, ")"c : o &= c
    150. Case "n"c : o &= vbLf
    151. Case "r"c : o &= vbCr
    152. Case "t"c : o &= vbTab
    153. Case "b"c : o &= vbBack
    154. Case "f"c : o &= vbFormFeed
    155. Case "0"c To "7"c
    156. nnn &= c
    157. If nnn.Length = 3 Then
    158. o &= Convert.ToChar(Convert.ToInt16(nnn, 8))
    159. nnn = ""
    160. Else
    161. Esc = True
    162. End If
    163. End Select
    164. Else
    165. If c = "\" Then Esc = True Else o &= c
    166. End If
    167. Next
    168. Return o
    169. End Function
    170. End Class

    Scheint die Texte zumindest ganz gut zu erkennen.
    Die UnEscape und UnGlyphe Funktionen muss ich vielleicht noch durch RegEx ersetzen, aber auf die Schnelle ging es so ganz gut.

    @ErfinderDesRades
    Ich habe allerdings in deinen veröffentlichten Fragmenten keine Tabellenstruktur erkannt.
    Das scheint nur der Rechnungskopf zu sein.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „petaod“ ()

    huch - ich bin jetzt auch ganz erschrocken, dass du da wirklich Inhalte ausgelesen hast. 8|
    Weil das kann ich eiglich nicht bringen, hier den Wortlaut iwelcher Rechnungen ins Inet zu stellen.
    Und ja, das war nicht der vollständige pdf-Code.

    So, und wenn ich das Englische recht verstehe, sind da iwie tatsächlich Positions-Angaben reingehudelt - hmm hmm - kann ganz schön frickelig werden...
    Keine Angst, ich werde die Information für mich behalten ;)

    Lass mal deine einzelnen Pages durch die ​Function Fields aus Post #16 durch.
    Dann müsstest du die Textelemente kriegen.

    Nachdem das eine Projekt nun brauchbar läuft, habe ich gleich noch zwei andere PDF-Projekte auf den Schreibtisch gekriegt.
    Es sieht so aus, dass ich die Klasse noch mit etwas Intelligenz erweitern muss.
    Vielleicht habe ich auch nur die Struktur und die Strategien des PdfTextExtractor in iTextSharp noch nicht verstanden.
    Von dem würde ich eigentlich solche Dinge erwarten,
    Aber meine bisherigen Fehlversuche haben mich dazu veranlasst, das Parsen selbst in die Hand zu nehmen.
    Vielleicht wird ja im Lauf der Zeit sogar eine vernünftiger universeller Parser draus.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    @ErfinderDesRades
    Und der Firmenname war auch zu erkennen, es hat zwar die Umsatzsteuernummer gefehlt... ;)

    @petaod
    Mir sind nur zwei Strategien vom PDFTextExtraktor bekannt. SimpleTextExtractionStrategy und LocationTextExtractionStrategy beides hier eher ungeeignet.

    petaod schrieb:

    Aber meine bisherigen Fehlversuche haben mich dazu veranlasst, das Parsen selbst in die Hand zu nehmen.

    Halte ich für den jeweiligen Anwendungsfall das Beste.

    Aber mal spontan Quer gedacht:
    Die PDF in eine .xml und dann die .xml auslesen? Bitte nicht direkt steinigen... Hab gerade meine kreative Phase ;)