OCR - Rechnungserkennung, wie geht das genau?

beta20

Top Contributor
Hallo zusammen,

ich würde gerne eine automatische Rechnungserkennung programmieren.
Ich frage mich jedoch gerade wie das technisch genau abläuft, wie erkennt mein OCR den Rechnungsbetrag, Datum etc.?

Hier meine Idee...
1) Ich scanne ein PDF / Image ein
2) Jage das über den OCR (z.B. Tessa4j OCR).
3) Nun erhalte ich einen String zurück
4) Ich prüfe den String nun auf verschiedene String ab (z.B. "Rechnungsdatum", "Rechnungsbetrag"; dahinter sollte dann i.d.R. der Rechnungsbetrag etc. stehen...
5) Wie erhalte ich den Betrag / Datum aber nun?

Danke für jede Hilfe.
 

httpdigest

Top Contributor
Das Ganze kann sich von relativ einfach bis seeehr seeehr schwer gestalten. Angenommen, das PDF verwendet eine Art tabellarischen Aufbau der Rechnungspositionen mit Linien hier und dort und dem tatsächlichen Rechnungsbetrag unter irgendeiner doppelt gestrichelten Linie (die z.B. vom OCR Tool als mehrere Gleichheitszeichen interpretiert werden könnte).
Es hängt zu 100% von dem tatsächlich verwendeten Image/PDF ab und auch von den OCR Einstellungen (z.B. DPI, ob nur Text oder auch Bilderkennung, etc.).
Du musst es also einfach mal ausprobieren und "gucken", was für ein String da dann herauskommt. Dann kannst du dir z.B. einen regulären Ausdruck überlegen, oder einfach per string.indexOf("Rechnungsbetrag") den Index im Text heraussuchen und dann mit einem Offset den Wert extrahieren, falls dieser denn dahintersteht.

Optimalerweise sollte man aber für Maschine-zu-Maschine Kommunikation ein strukturiertes Datenformat, z.B. XML oder JSON, verwenden. PDFs sind ja eher für Maschine-zu-Mensch Kommunikation gedacht: Maschine druckt PDF aus -> Mensch interpretiert den Inhalt. Falls das System, was dir das PDF generiert, also solch eine Schnittstelle anbietet, ist das auf jeden Fall zu bevorzugen.
 

mihe7

Top Contributor
Da kann @httpdigest nur uneingeschränkt Zustimmen. Wir haben das mal mit PDFs versucht, in denen die Zeichen (keine Zeichenketten!) sogar extrahiert werden konnten. Die Dinger waren nicht gescannt sondern erzeugt worden.

Man konnte also eine Liste von Positionsangaben und dem dazugehörigen Zeichen erhalten. Selbst da ist es ein Ding der "Unmöglichkeit", einen einfachen Algorithmus anzugeben, der das Problem löst.

Das fängt schon damit an, dass die Wortabstände teilweise nicht von Zeichenabständen zu unterscheiden sind. Die Bündigkeit von Spalten in Tabellen ist ebenfalls kaum zu erkennen. Rechtsbündigen Zellen sind mit den Daten überhaupt nicht erkennbar, weil im PDF die Koordinate von links angegeben wird usw. Dann gibt es das Problem, dass Tabellen über mehrere Seiten gehen etc. etc.

Man muss also eine gehörige Portion Aufwand in die Sache stecken, um eine Lösung zu finden.

Es gibt allerdings Tools, die in der Lage sind, einen Scan z. B. in ein Word- oder Excel-Dokument umzuwandeln. Wenn das gut funktioniert, kann man damit natürlich weiterarbeiten.
 

beta20

Top Contributor
Ok, danke.

Ich brauche den Scan nicht als Word / Excelfile.
Ich will lediglich aus dem Scan / Datei die verschiedenen Informationen aus einer Rechnung herausbekommen (Betrag, Datum...).
Was ich mich nun allerdings frage, lohnt sich der Aufwand überhaupt das selbst zu programmieren?
Es gibt doch sicherlicht Dienste mittlerweile, die das für einen übernehmen können, die man dann mit einer REST API ansprechen kann? Oder sieht ihr das anderst?
 

mihe7

Top Contributor
Es gibt doch sicherlicht Dienste mittlerweile, die das für einen übernehmen können, die man dann mit einer REST API ansprechen kann?
Ich wage zu bezweifeln, dass es schon einen Dienst gibt, dem Du irgendeinen Scan zuschickst und der Dir dann Anwortet: Hey, das ist eine Rechnung. Die hat die Nummer 421 vom Kunden X, geschrieben am 12.12.2017, mit einem Gesamtbetrag von 123 €. In Position 1 - der Kaffeemaschine - sind 19 % MwSt enthalten. Überwiesen soll der Betrag auf die IBAN DExxxxx werden. Dabei ist als Verwendungszweck 2421/421 anzugeben, der Geschäftsführer ist der Bürgermeister Krause, geliefert werden soll aber an den Hausmeister... aber wer weiß, vielleicht ist die KI ja schon so weit :)

Was ich weiß: es gibt Dienste (wie auch Programme), mit denen man ein PDF z. B. in Text, Excel, ... umwandeln kann. Ob die einen Webservice anbieten, weiß ich nicht. Die benötigten Daten musst Du Dir dann selbst rausziehen.
 

beta20

Top Contributor
Es gibt Programm (z.B. SevDesk), die machen sowas doch schon (ausgenommen die automatische Überweisung)

Prinzipiell brauche ich ja "nur":
a) Den String der PDF (Scan)
b) Funktion, die mir dann bestimmte Typen inkl. Wert liefert: also z.B. :
-> Suche ich nach "Rechnungsbetrag" in meinem String (den ich vom Scan erhalte), dann soll eben der entsprechende Wert (5,00 EUR) zurückgegeben.

Also sowas wie:
Java:
public String findValue(String value) {
....
}
-> Value ist dann der komplette String, den ich dann durch den OCR zurückbekomme.

Mein Problem ist Stand heute den Wert zu bekommen (also z.B. "5,00EUR" von "Rechnungsbetrag").
 

Axolis

Neues Mitglied
Hey, beta20.
Ich programmiere im Augenblick genau eine solche Geschichte als interne Software in einem Unternehmen.
Besonders bei der Ermittlung des Rechnungsbetrages kannst Du mit "gewöhnlichen" Mitteln wie String.contains() oder anderen "einfachen" Parsingversuchen nicht viel anfangen, da Du (wie hier auch schon gesagt wurde) nie wissen kannst, wo genau der Betrag jetzt steht. Manchmal erhältst Du sicher "Rechnungsbetrag EUR 5,00". meistens wird es aber irgendwie anders sein.
- es steht nichts vor dem gesuchten Wert
- es steht ein anderes Wort davor (Betrag, Summe, gesamt, total, Saldo, ...)
- Der Wert steht nicht in derselben Zeile wie das Wort "Rechnungsbetrag"
usw usw usw.
Da braucht es schon heftigere Geschütze, um ein solches Muster zu erkennen...

Grüße,
Axolis
 

mihe7

Top Contributor
Es gibt Programm (z.B. SevDesk), die machen sowas doch schon (ausgenommen die automatische Überweisung)
Stimmt. Es gibt auch Banken, die damit werben, dass man eine Überweisung per Foto von der Rechnung ausführen kann... Ich wage aber auch hier zu bezweifeln, dass das immer vollautomatisch funktioniert.

Worum es mir geht ist einfach folgendes: je unterschiedlicher die Rechnungen aufgebaut sind, um so komplizierter wird die Geschichte. Man kommt ziemlich schnell an den Punkt, wo es mit "einfachen Abfragen" nicht mehr weitergeht.

Wenn Du Dir eine Rechnung anschaust und Dir als String vorstellst, dann könnte z. B. bei der einen Rechnung "Rechnungsbetrag: 5,00 €" stehen, bei der nächsten dagegen "Gesamtbetrag MwSt\n 5,00 € 0,95 €" und das sind noch die einfachen Geschichten.
 

beta20

Top Contributor
Hi Axolis,
danke für deine Antwort.
Dass das nicht immer 100% funktioniert, ist mir auch klar - da es immer wieder Ausnahmen geben wird.
Angefangen von anderen Wörtern: (Betrag, Summe, gesamt, total, Saldo, ...)

Da braucht es schon heftigere Geschütze, um ein solches Muster zu erkennen...
Grüße,
Axolis
Was genau meinst du damit? Wie gehst du das Ganze an?
 

Meniskusschaden

Top Contributor
5) Wie erhalte ich den Betrag / Datum aber nun?
Die Rechnungen können je nach Lieferant ja sehr unterschiedlich aussehen. Deshalb würde ich auf jeden Fall eine konfigurierbare Lösung vorsehen, die es ermöglicht, zunächst den Lieferanten zu erkennen, damit das Extrahieren der Inhalte dann spezifisch für den Lieferanten erfolgen kann. Dabei würde ich nicht nur feste Zeichenfolgen, sondern unbedingt auch reguläre Ausdrücke zulassen, die man auf den OCR-Text anwendet. Damit kann man oft eine ganze Menge erreichen. So könnte man beispielsweise anhand der Umsatzsteuer-ID DE123456789 den Lieferanten X zuverlässig identifizieren, bei dessen Rechnungen über den regulären Ausdruck \b\d{4}\/\d{6}\b etwa die Rechnungsnummer 2018/123456 erkannt wird, die immer zwei Wörter links vom Rechnungsdatum steht. Für Rechnungsbeträge bietet sich eine Zusatzfunktion an, die typische Währungsbeträge erkennt und darunter den höchsten auswählt. Wenn man dann noch die Netto- und/oder MWSt.-Beträge ausliest kann man durch eine einfache Rechnung feststellen, ob der Betrag praktisch sicher stimmt oder möglicherweise falsch sein kann.
 

stg

Top Contributor
Ganz viel der "automatiersten Rechnungserkennung" erfolgt selbst bei professionellen, kommerziellen Lösungen, immer noch per Post nach Fern-Ost :oops:

Dass das nicht immer 100% funktioniert, ist mir auch klar -

Wenn du jetzt selbst etwas schreibst sollte deine Erwartungshaltung eher die sein, "dass es ab und an mal funktioniert ... vielleicht".

Was ich mich nun allerdings frage, lohnt sich der Aufwand überhaupt das selbst zu programmieren?
Es gibt doch sicherlicht Dienste mittlerweile, die das für einen übernehmen können, die man dann mit einer REST API ansprechen kann? Oder sieht ihr das anderst?

Gibt es, aber alles was ich kenne kostet die ein oder andere Mark....
Wenn du dich auf wenige, klar definierte "Rechnungsdesigns" beschränkst, dann könnte das klappen (du hast z.B. nur drei Lieferanten, deren Rechnung immer gleich aufgebaut ist)
Wenn es allerdings eine "allgemeine" Lösung werden soll, dann kannst du es quasi vergessen. Es gibt ganze Unternehmen, die sich genau um solche Aufgaben kümmern und schon jahr(zehnt)e-lang, an ihren immer noch nicht vollständig ausgereiften Lösungen arbeiten...
 

Thallius

Top Contributor
Mal ein ganz anderer Ansatz. Man nehme alle Beträge in der Rechnung und merke sich die Position. Dann testet man wie sich die zueinander verhalten. Also z.b. Von oben nach unten addieren bis die Summe irgendeinem weiter unten stehenden wert entspricht. Dann hat man die endsumme. Nun noch schauen ob diese die höchste Summe ist. Wenn nicht sucht man noch nach der MwSt Summe die dann die höchste Summe ergibt. Auf die gleiche Weise kann man nach Rabatten suchen etc.
Ist Aufwendung und fast schon bischen KI könnte aber klappen

Gruß

Claus
 

Meniskusschaden

Top Contributor
Mal ein ganz anderer Ansatz.
Bei dem Ansatz finde ich zwei Dinge schwierig:
1. Man benötigt Strukturinformationen, um zu erkennen, welche Werte übereinander stehen.
2. Man verarbeitet ziemlich viele Werte, so dass die Wahrscheinlichket, dass OCR-Fehler enthalten sind, relativ hoch ist.

Deshalb würde ich lieber versuchen, ob der ganz primitive Ansatz nicht vielversprechender ist: Der OCR-Text wird nur als flache Zeichenfolge aufgefasst. in der es kein oben und unten gibt, sondern nur ein links und rechts. Darin versucht man dann anhand von Mustern seine Ankerpunkte zu finden. Ein Customizing pro Lieferant wird man vermutlich ohnehin machen müssen.
 

Tarrew

Top Contributor
Hab über ein ähnliches Thema meine Bachelorarbeit geschrieben und finde den Ansatz, mit gewissen Strukturinformationen zu arbeiten, nicht schlecht.

Ein ganzes Bild in Tesseract zu hauen und dann den versuchen den Output irgendwie zu interpretieren ist mMn. fast unmöglich. Vor allem sobald Zahlen und Texte in Tabellen stehen, irgendwelche Querbalken vorhanden sind etc, kriegt man viel Müll oder garnichts aus Tesseract raus.

Als einfache Variante würde ich mal probieren OpenCV zu verwenden, um Textbausteine zu erkennen (z.B. EAST text detection). Die gefundenen Texte haut man dann jeweils in Tesseract.
Danach kann man dann evtl. mit gewissen Heuristiken arbeiten. Wenn du ein bestimmes Schlüsselwort a la "Rechnungsbetrag" oder Ähnliches findest und entsprechend die Koordinaten der Box hast, würde ich davon ausgehen, dass der Betrag irgendwo rechts, bzw. unterhalb vorhanden ist. Also xBetrag >= xRechnungsbetragString & yBetrag >= yRechnungsbetragString.

Je "näher" am gefundenen String eine Zahl dann ist, desto warscheinlicher vermutlich die Zugehörigkeit.

Bin zwar am Ende auch in die KI-Schiene gerutscht, aber mit dem "primitiven" Ansatz ließen sich schon akzeptable Ergebnisse verzeichnen. Natürlich nicht mit einer Genauigkeit, mit der man es zuverlässig & kommerziell hätte einsetzen können ;)
 

Meniskusschaden

Top Contributor
@Tarrew : Der TE will ja nur Rechnungsbetrag und Rechnungsdatum haben. Dafür scheint mir das etwas überdimensioniert zu sein. Wenn man aber beispielsweise die Rechnungsdaten positionsweise verbuchen lassen wollte, wäre das eine ganz andere Geschichte für die man wahrscheinlich so einen Weg gehen müsste.
 

Tarrew

Top Contributor
Ich denke nur gerade daran, dass viele Rechnungen in Tabellenform sind, Symbole aufweisen, Querbalken etc.
So ein Bild unverarbeitet einfach in Tesseract reinzuschmeissen ist schon mutig.

Tesseract schafft es nicht Text auszulesen, der innerhalb von Boxen oder irgendwelchen Formen ist.
Irgendeine Form von Vorverarbeitung wird man in solchen Fällen also ohnehin machen müssen.
Evtl. Line-Removal mit Leptonica etc, aber dann ist OpenCV nicht mehr weit weg und auch nicht viel komplizierter.

Wäre natürlich schick mal 2, 3 Musterrechnungen zu sehen, um mal einen Eindruck davon zu bekommen.
 
X

Xyz1

Gast
Vor allem sobald Zahlen und Texte in Tabellen stehen, irgendwelche Querbalken vorhanden sind etc, kriegt man viel Müll oder garnichts
Wieso dass denn? Du hast doch schon was von Text respektive Zeichenerkennung gehört nehme ich an? Buchstaben und Ziffern lassen sich relativ schnell ausfindig machen und Zeichen eindeutig erkennen.... und zwar besser als ich sie erkennen kann

Wäre natürlich schick mal 2, 3 Musterrechnungen zu sehen, um mal einen Eindruck davon zu bekommen
Erstelle Dir doch ein paar, es gibt für sowas kein einheitliches Format jeder Handwerker kann das selbst machen....

Oben steht meist irgendein name, in der mitte die RechnungsPositionen und unten rechts das was sie Dir abziehen....

Mit diesen Informationen ist ein customizing fast hinfällig.
 

Axolis

Neues Mitglied
Es gibt Tricks, Workarounds, Methoden.
ich arbeite mit zonaler Erkennung, Mustererkennung, Textanalyse, und noch einem gerüttelt Maß reiner Magie...

es bleibt schwer !

VG,
Axolis.
 

Meniskusschaden

Top Contributor
Tesseract schafft es nicht Text auszulesen, der innerhalb von Boxen oder irgendwelchen Formen ist.
Ich weiß jetzt nicht, was hier mit Boxen gemeint ist und habe deshalb eben mal testweise eine Papierrechnung eingescannt, deren Summenbereich sich in einem umrandeten Bereich befindet, der noch ein wenig untergliedert ist. Den enthaltenen Text hat Tesseract schon recht gut erkannt. Vielleicht meinst du mit den Boxen aber auch etwas komplizierteres - etwa mit farbigem oder schraffierten Hintergrund oder so. Das wäre meines Erachtens aber eher untypisch für Rechnungen.
 

Meniskusschaden

Top Contributor
Wäre natürlich schick mal 2, 3 Musterrechnungen zu sehen, um mal einen Eindruck davon zu bekommen.
Das lässt sich natürlich wirklich besser mit echten Beispielen diskutieren. Aber nach meiner Erfahrung wird man das zur Einführung für die wichtigsten Lieferanten gemeinsam mit dem Anwender bzw. Kunden einstellen und danach bleibt es eine dauerhafte Aufgabe, sich schlecht erkannte Rechnungen anzusehen und die Konfiguration zu verbessern (oder zu entscheiden, dass es sich für den Lieferanten nicht lohnt). Das sehe ich aber als Aufgabe des Anwenders/Kunden.
 

Senftube

Aktives Mitglied
Such mal im web nach xpdf (opensource) dort gibt es in einem Unterverzeichnis auch diverse Kommandzeilenversionen u.a.
z.B eine pdftotext.exe
mit der Text im pdf auf eine textdatei extrahiert wird. Das kann man gut in einem java programm
aufrufen. Mit folgends args hab ich die besten erfahrungen gemacht. Die Args hab ich in meiner Anwendung konfigurierbar gemacht.

s = props.getProperty("PDF_TO_TEXT_ARGS","-eol dos -bom \"{0}\" \"{1}\""); // 0=pdffile 1=outfile

Die -bom option erzeugt trotzdem kein BOM im outputfile
 

beta20

Top Contributor
Also ich habe Tessa4j jetzt mal installiert. Das funktoniert nun auch soweit.

Folgendes bekomme ich heraus:
Java:
Karl Klimm
Holleweg 7
12345 DEMOSTEDT
Rechnung
Rechnungsnummer Zahlungsziel ~~ Leistungszeitraum Rechnungsdatum
5be18f9781b1f20928284969 07.11.2018 01.11.2018 00:00- 30.11.2018 23:59 06.11.2018
Bezeichnung (VIET T=4 (Idee MwSt. % VIALS Netto
Einrichtungsgebihr 1 50,00 19 9,50 50,00
01.11.2018 00:00
Mein Produkt - Advanced 1 75,00 19 14,25 75,00
enthalt alle basic-Funktionen plus das Feature Deluxe pro Monat
monatliche Laufzeit und monatliche Zahlung
01.11.2018 00:00 - 01.12.2018 00:00
Gesamt Netto 125,00
MwSt. 19% 23,75
Gesamtbetrag EUR 148,75

Wie bekomme ich nun die wirklichen Dinge, die ich brauche.
Beispiel:
Java:
Gesamtbetrag EUR 148,75

-> Nun will ich nur
Betrag: 148,75
Currency: EUR
....

Wie gehe ich hier voran?
 

mihe7

Top Contributor
Java:
String line = "Gesamtbetrag EUR 148,75";
String[] parts = line.split(" ");
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(Locale.GERMAN);
df.setParseBigDecimal(true);
BigDecimal value = (BigDecimal) df.parse(parts[2]);
String currency = parts[1];
 

Meniskusschaden

Top Contributor
Wie gehe ich hier voran?
Z.B. mit regulären Ausdrücken:
Java:
        String regExp = "Gesamtbetrag ([A-Z]{3}) (\\d+,\\d\\d)";     
        int iCurrency = 1;
        int iAmount = 2;

        String text = "vvv yvä vöä g gdfsg dfs Gesamt Netto 125,00 MwSt. 19% 23,75 Gesamtbetrag EUR 148,75";
        Matcher matcher = Pattern.compile(regExp).matcher(text);
        matcher.find();
        System.out.println(matcher.group(iCurrency));
        System.out.println(matcher.group(iAmount));
Dann kannst du leicht beliebig viele Regeln in eine Konfigurationsdatei auslagern. Eine Regel könnte aus einem regulären Ausdruck und einer Liste von Gruppenindizes bestehen, die die Gruppen des regulären Ausdrucks dem jeweils entsprechenden Wert zuordnen.
Darüber hinaus könntest du - falls die Rechnungen sich unterscheiden - mehrere solcher Regelsätze definieren und den jeweils passenden - wiederum anhand eines regulären Ausdrucks - vorab auswählen lassen.
 

beta20

Top Contributor
also mein Ansatz ist das als "Machinelearning" aufzuziehen.
Das Programm wird leben und immer mehr erweitert, da die Rechnungen werden auf keinen Fall immer gleich aussehen.

Im Prinzip benötige ich ja immer folgende Informationen:
- Rechnungsnummer
- Rechnungsdatum
- Nettopreis
- Bruttopreis
- Währung
- Fälligkeit

- Lieferant
- BIC
- IBAN
- Straße
- PLZ
- Land

Im groben Ablauf suche ich dann pro Rechnung immer nach diesen Informationen.
Hierzu habe ich dann pro Information eine Funktion

Java:
public String findRechnungsnummer(String stringFromInvoice){}
public String findRechnungsdatum(String stringFromInvoice){}

Folgende Idee schwebt mir vor:
Ich lege mehrere DB-Tabellen an um die Dinge zu ermitteln.

1) Invoice_Regex
ID,
Regex, -> Beispiel: Gesamtbetrag ([A-Z]{3}) (\\d+,\\d\\d)
Example, -> Beispiel: Gesamtbetrag EUR 126,00
Type -> handelt es sich um den Rechnungsbetrag, Rechnungsdatum...
languageCode -> Sprache

Nun wird bspw. in der Funktion
Java:
public String findRechnungsnummer(String stringFromInvoice){}

alle Einträge der Tabelle vom Typ "Rechnungsnummer" geholt.
Innerhalb einer Schleife werden dann die Regex durchgegangen:

Java:
String regExp = entry[i].regex;  
int iCurrency = 1;
int iAmount = 2;

-> Sobald es ein Match gibt, wird die Methode beendet und die weitere Informationen der Rechnung werden gesucht...

Eine zweite Tabelle könnte die Lieferanten speichern.
-> Dies könnte dazu dienen, dass man die Branche des Lieferanten und demnach den Typ (Hostinggebühren, Hotelkosten...) direkt vorschlagen kann.

2) Invoice_Vendor
ID
Name
Country
...

3) BelegTyp
Bsp. Hosting, Hotel....

Ist das eine gute Idee das so zu machen oder gibt es andere Vorschläge / Verbesserungen?

Wenn ich das richtig verstehe, ist die Challenge eig. nun die passenden RegexExpressions zu erstellen?
 

Meniskusschaden

Top Contributor
also mein Ansatz ist das als "Machinelearning" aufzuziehen.
Von "Machinelearning" verstehe ich nicht viel. Ich würde da aber mit unverhältnismäßig großem Entwicklungsaufwand rechnen und auch erwarten, dass die Ursachen schlechter Ergebnisse schwieriger zu ermitteln und zu beseitigen sind. Ich bevorzuge eindeutig manuell gepflegte Erkennungsregeln. Bei schlechten Ergebnissen sieht man sich den OCR-Text an und überlegt sich, welche Ausdrücke man etwas tolerenter oder schärfer gestaltet.

Im groben Ablauf suche ich dann pro Rechnung immer nach diesen Informationen.
Hierzu habe ich dann pro Information eine Funktion
Java:
public String findRechnungsnummer(String stringFromInvoice){}
public String findRechnungsdatum(String stringFromInvoice){}
Folgende Idee schwebt mir vor:
Ich lege mehrere DB-Tabellen an um die Dinge zu ermitteln.
Ich glaube, das wäre mir vielleicht nicht generisch genug. Ich würde nicht einzeln "Gib mir die Rechnungsnummer!", "Gib mir das Datum!" etc. aufrufen wollen, sondern "Gib mir alles, was du findest!". Aber vielleicht ist dein Weg auch pragmatischer. Für die Inhouse-Programmierung muß nicht immer alles generisch sein.

Nun wird bspw. in der Funktion
Java:
public String findRechnungsnummer(String stringFromInvoice){}
alle Einträge der Tabelle vom Typ "Rechnungsnummer" geholt.
Innerhalb einer Schleife werden dann die Regex durchgegangen:
Java:
String regExp = entry[i].regex;
int iCurrency = 1;
int iAmount = 2;
-> Sobald es ein Match gibt, wird die Methode beendet und die weitere Informationen der Rechnung werden gesucht...
Ich würde das genau anders herum machen, denn ich finde es nicht sehr erfolgversprechend, einfach alle Möglichkeiten für die Rechnungsnummer durchzuprobieren. Es ist viel zu wahrscheinlich, dass ein Suchmuster, das für Lieferant A gut passt, auch bei Lieferant B matcht, jedoch einen falschen Wert liefert. Es ist schwierig, universelle Regeln zu finden. Es ist aber ziemlich einfach, den Lieferanten zu identifizieren. Und bei sehr vielen Lieferanten wird es auch einfach sein, die gewünschten Infos zu extrahieren, wenn man denn weiß, dass es dieser Lieferant ist.

Also noch einmal mein Vorschlag:

Schritt 1: Den Lieferanten der Rechnung identifizieren.
Das lässt sich leicht mit regulären Ausdrücken bewerkstelligen. Hier wäre auch eine Automatisierung denkbar, wenn man einfach eine ODER-Verknüpfung für die typischen Kandidaten wie Steuernummern, Bankverbindungen, Internet-Domänen etc. aus den ERP-Stammdaten generiert. Es sind aber noch genug Fehlerquellen denkbar, etwa aufgrund unterschiedlicher Formatierungen. Deshalb würde ich auch das zunächst manuell machen und Erfahrungen sammeln.

Schritt 2: Rechnungsdaten nach individuellen Regeln des Lieferanten ermitteln.
Hier würde ich dauerhaft bei manuell erstellten Regeln bleiben. Für diesen Lieferanten gibt es dann nicht x Ausdrücke für das Rechnungsdatum, sondern nur einen, der exakt zugeschnitten ist. Den OCR-Text wird man ja ohnehin mit dem Dokument abspeichern. Bei schlechten Ergebnissen sieht man sich ihn an, prüft die Regeln, passt sie an und ruft einen Refresh auf, um die Werte neu zu ermitteln und damit die Regeln zu prüfen.

Wenn ich das richtig verstehe, ist die Challenge eig. nun die passenden RegexExpressions zu erstellen?
Ja. Die eine Hälfte der Funktionalität schenkt einem die OCR, die andere Hälfte die RegEx. Für die eigentliche Verarbeitung ist kaum etwas zu programmieren.
 

beta20

Top Contributor
Danke Dir.

Mit "machinelearning" meine ich auch eher (vllt. ist der Begriff an der Stelle nicht ganz korrekt):
- user scannt Dokument ein
- OCR läuft drüber
- Rechnungsdaten werden nicht erkannt
- User kann über das Bild der Rechnung einen Bereich definieren und dann definieren, das ist meine "Rechnungsnr" z.B.
- Anschließend wird dies in eine Tabelle geschrieben, dass die Rechnung nicht erkannt wurde
- Ein Admin kann dann prüfen, warum diese nicht erkannt wurde und ggf. das Programm erweitern / Tabelleneintrag hinzufügen...

Was verstehst du mit "Inhouse Programmierung" ?

OK, das ist auch ein guter Vorschlag von dir.
Ich verstehe es dann so, dass man in der Lieferanten - Tabelle ebenfalls die Regex - Funktionen der verschiedenen Dinge speichert, sodass man diese bei einer erneuten Rechnung schnell im Zugriff hat?
Natürlich könnte ein Lieferant seine Rechnung ändern, dann müsste man den Eintrag in der Tabelle wieder anpassen...
Ggf. kann ein Lieferant auch mehrere Rechnungsdesign haben.

Also um es zusammenfassen:
1) Lieferant suchen (per Steuernummer / Bankverbindung / Homepage)
2) Prüfen, ob schon in Lieferanttabelle vorhanden
3) Wenn ja: Regex - Funktionen des Lieferant anwenden, die in der Tabelle gespeichert wurde
4) Wenn nein: "allgemeine Regex - Funktionen" anwenden, die aus einer seperaten Tabelle kommen + Lieferant in die Tabelle aufnehmen


Eine weitere Frage noch:
User1:
- scannt Dokument ein
- Lieferant gibt es noch nicht
- Lieferant wird in die DB - Tabelle aufgenommen und und Kategorie "Hotel" gespeichert


User2:
- scannt Dokument vom gleichen Lieferant ein
- Lieferant gibt es schon und die Regex - Funktionen werden verwendet, Rechnungsinfos wird auch erkannt etc.
- User definiert aber eine andere Kategorie "Hoster"

Wie kann ich damit umgehen? Ggf. kann ein Lieferant auch aus unterschiedlichen Branchen kommen.
Sollte ich hier ein Rank anwenden über alle Belege mit dem Lieferanten.
Die Anzahl mit den meisten gleichen Branchen wird dann standardmäßig übernommen?
 

Meniskusschaden

Top Contributor
User kann über das Bild der Rechnung einen Bereich definieren und dann definieren, das ist meine "Rechnungsnr" z.B.
Solche Funktionen werden den größten Aufwand ausmachen und für mich ist fraglich, ob es wirklich einen großen Nutzen bringt. Es ist ja nicht trivial, daraus eine brauchbare Regel abzuleiten, die das auch bei anderen Rechnungen des Lieferanten erkennt. In der Praxis würde man wahrscheinlich einfach das OCR-Ergebnis in einen RegEx-Tester kopieren, dort einen Ausdruck aufbauen, der für das Beispiel matcht und überlegen, welche Teile wirklich konstant und welche variabel sind. Ich würde erst einmal fast nichts entwickeln, sondern als Proof of Concept die Regeln für ein paar Lieferanten an echten Belegen ausprobieren.

Was verstehst du mit "Inhouse Programmierung" ?
Damit meine ich die Programmierung für das eigene Unternehmen und bis zu einem gewissen Grad auch individuelle Auftragsprogrammierung für einen Kunden. Also eben keine Standardsoftware, die für viele Kunden anpassbar sein muss.

Ich verstehe es dann so, dass man in der Lieferanten - Tabelle ebenfalls die Regex - Funktionen der verschiedenen Dinge speichert, sodass man diese bei einer erneuten Rechnung schnell im Zugriff hat?
Natürlich könnte ein Lieferant seine Rechnung ändern, dann müsste man den Eintrag in der Tabelle wieder anpassen...
Ggf. kann ein Lieferant auch mehrere Rechnungsdesign haben.

Also um es zusammenfassen:
1) Lieferant suchen (per Steuernummer / Bankverbindung / Homepage)
2) Prüfen, ob schon in Lieferanttabelle vorhanden
3) Wenn ja: Regex - Funktionen des Lieferant anwenden, die in der Tabelle gespeichert wurde
4) Wenn nein: "allgemeine Regex - Funktionen" anwenden, die aus einer seperaten Tabelle kommen + Lieferant in die Tabelle aufnehmen

Ich würde es im eigentlichen Kern der Dokumentenverarbeitung vermeiden, direkte Abhängigkeiten zu Lieferantentabellen und ähnlich spezifischen Dingen zu schaffen, denn eigentlich kann man davon ganz unabhängig bleiben und die Funktionalität dann auch für ganz andere Dokumentarten verwenden (oder auch dafür, überhaupt die Dokumentart zu erkennen und unsortierte Eingangspost zu ordnen).
Für mich wäre das Ziel, ein Dokument in die Dokumentenverarbeitung werfen zu können und eine Liste mit Schlüssel/Wert-Paaren zurück zu bekommen. Dieses Ergebnis kann man dann ja im konkreten Kontext der Rechnungsverarbeitung spezifisch weiter verarbeiten. Aber innerhalb der Dokumentenverarbeitung würde ich universell bleiben. Als Beispiel könnten zwei Tabellen genügen:
Code:
Tabelle PATTERN_SETS:

ID  NAME                 REGEX                      Erläuterung
1   Klimm-Rechnung       Karl Klimm|DE123456789     Identifikation anhand Name oder Umsatzsteuer-ID
2   Mustermann-Rechnung  DE987654321|02\/815\/4711  Identifikation anhand Umsatzsteuer-ID oder Steuernummer


Tabelle PATTERNS:

ID  PATTERN_SET  NAME             REGEX                                  GROUP  Erläuterung
1   1            Rechnungsnummer  (\b\w{24}\b)                           1      Rechnungsnummer für Klimm ist ein Wort aus 24 Zeichen
2   1            Rechnungsdatum   \d\d:\d\d (\d\d\.\d\d\.\d{4})          1      Rechnungsdatum für Klimm ist ein Datum, das auf eine Uhrzeit folgt
3   1            Währung          Gesamtbetrag (\w{3}) (\d+,\d\d)        1      Die Währung für Klimm sind drei Buchstaben zwischen dem Wort "Gesamtbetrag" und einem Betrag
4   1            Betrag           Gesamtbetrag (\w{3}) (\d+,\d\d)        2      Der Betrag für Klimm ist ein Betrag hinter dem Wort "Gesamtbetrag" und der Währung
5   2            Rechnungsnummer  \b(\d{4}-\d{5})\b                      1      Eine Rechnungsnummer für Mustermann könnte so aussehen: 2018-12345
6   2            Rechnungsdatum   Rechnungsdatum.*?(\d\d\.\d\d\.\d{4})   1      Ein Rechnungsdatum für Mustermann könnte das erste Datum nach dem Wort "Rechnungsdatum" sein
Man kann das dann ohne Weiteres für ganz andere Dokumentarten benutzen. Es spricht auch nichts dagegen, für einen Lieferanten zwei Regelsätze oder einen Regelsatz für mehrere Lieferanten zu verwenden. Auch mehrere Muster für dasselbe Schlüsselfeld innerhalb eines Regelsatzes sind möglich. Es kann auch sinnvoll sein, bei PATTERN_SETS und PATTERNS nicht nur den jeweils ersten Match zu verwenden, sondern alle.

Man könnte natürlich noch viele Zusatzfunktionen ergänzen. Anhand problematischer Belege wird man erkennen, was da wirklich nützlich wäre. Deshalb würde ich am Anfang nicht übertreiben.

Eine weitere Frage noch:
User1:
- scannt Dokument ein
- Lieferant gibt es noch nicht
- Lieferant wird in die DB - Tabelle aufgenommen und und Kategorie "Hotel" gespeichert


User2:
- scannt Dokument vom gleichen Lieferant ein
- Lieferant gibt es schon und die Regex - Funktionen werden verwendet, Rechnungsinfos wird auch erkannt etc.
- User definiert aber eine andere Kategorie "Hoster"

Wie kann ich damit umgehen? Ggf. kann ein Lieferant auch aus unterschiedlichen Branchen kommen.
Sollte ich hier ein Rank anwenden über alle Belege mit dem Lieferanten.
Die Anzahl mit den meisten gleichen Branchen wird dann standardmäßig übernommen?

Na ja, ich denke, das hängt schon von dem Zweck der Kategorie ab. Wenn das einfach eine Klassifizierung für den Lieferanten sein soll, muß man sich eben überlegen, ob man nur eine zulassen will oder mehrere und benötigt ein dazu passendes Datenmodell.
Wenn es darum geht, die Rechnung zu klassifizieren und das bei demselben Lieferanten mal so und mal anders sein kann, bietet sich evtl. an, auch das anhand von Mustern zu erkennen. Außerdem muß man sich überlegen, ob auch eine Rechnung zwei Kategorien angehören kann. Dann muß das Datenmodell das eben auch ermöglichen. Für die eigentliche Erkennung der Kategorien würde ich da keine allzu großen Schwierigkeiten erwarten.
 

beta20

Top Contributor
Vielen Dank für die klasse Beschreibung.

Also wenn ich das richtige verstehe, wäre deine "Pattern-Set" quasi dein "Lieferant".
Dies müsste aber auf jeden Fall noch mit dem Typ erweitert werden, sodass die Rechnung / Beleg automatisch einer Kategorie zugeordnet werden kann (Hotelkosten, Hostinggebühren...)

Vom Ablauf des Programms verstehe ich das dann so:
1) Rechnung wird eingelesen
2) OCR Text wird erstellt
3) OCR Text wird nach dem Regex von Tabelle PATTERN_SETS durchsucht.
-> Wenn es ein Treffer gibt, dann werden alle Pattern aus der Tabelle PATTERNS angewendet um die benötigten Infos zu bekommen
4) Kann kein Pattern-Set angewendet werden, dann werden alle mögliche Pattern aus der Tabelle PATTERNS angewandt.
5) Mittels den gefunden Infos wie: Steuernummer / Name, wird dann ein neues PATTERN_SET erstellt

Meiner Meinung bräuchte man dann aber noch eine Zwischentabelle, die gleichen Patterns in der Tabelle PATTERN anzulegen, halte ich eher für unschön...???

PATTERN_SETS -> Die Lieferanten
PATTERNS -> mögliche Muser
PATTERN_SETS_PATTERN -> Zwischentabelle, sodass ein Lieferant mehrere PATTERNS nutzen kann
ID, PATTERN_SETS_FK, PATTERN_FK

Meines Erachtes müsste man die PATTERN - Tabelle auch noch um die Spalte "languageCode" erweitern.
Ein Lieferant (mit der gleichen Steuernummer) kann die Rechnung ja in Englisch, als auch in Deutsch ausliefern.
Durch eine Methode oder manuelle Auswahl des Users, wird dann eben der Sprachcode ermittelt.
Wenn die Rechnung in Englisch ist, dann werden eben PATTERN 1-2 angewandt, wenn in Deutsch, dann PATTERN 3-4. (PATTERN_SET_FK) ist jeweils der gleiche.
 
X

Xyz1

Gast
Ihr schreibt soviel dass man gar nicht Lust hat das alles zu sehen. ;)

Rechnungsbetrag kann überall anders sein, aber ist meist der höchste Betrag, deswegen würd ich da dem Meniskusschaden zustimmen und es nicht mit machine learning machen.
 

Meniskusschaden

Top Contributor
Also wenn ich das richtige verstehe, wäre deine "Pattern-Set" quasi dein "Lieferant".
Ja, nur eben universell und nicht auf Lieferanten beschränkt oder davon abhängig. Im Normalfall wird man für jeden Lieferanten genau ein Pattern-Set haben.
Dies müsste aber auf jeden Fall noch mit dem Typ erweitert werden, sodass die Rechnung / Beleg automatisch einer Kategorie zugeordnet werden kann (Hotelkosten, Hostinggebühren...)
Das kann ich noch nicht so richtig nachvollziehen. Ich hätte es wahrscheinlich eher über ein Pattern gelöst. Das würde evtl. noch eine einfache Ersetzungsfunktion erfordern (die aber ohnehin nützlich sein dürfte).
Vom Ablauf des Programms verstehe ich das dann so:
1) Rechnung wird eingelesen
2) OCR Text wird erstellt
3) OCR Text wird nach dem Regex von Tabelle PATTERN_SETS durchsucht.
-> Wenn es ein Treffer gibt, dann werden alle Pattern aus der Tabelle PATTERNS angewendet um die benötigten Infos zu bekommen
4) Kann kein Pattern-Set angewendet werden, dann werden alle mögliche Pattern aus der Tabelle PATTERNS angewandt.
5) Mittels den gefunden Infos wie: Steuernummer / Name, wird dann ein neues PATTERN_SET erstellt
Bis Punkt 3 stimme ich zu. Wenn es bis dahin keine Treffer gab, hat man eben nichts gefunden. Ich würde aber wahrscheinlich nicht nur das erste passende Pattern-Set ausführen, sondern alle passenden Sets. Die Punkte 4 und 5 würde ich weglassen.
Meiner Meinung bräuchte man dann aber noch eine Zwischentabelle, die gleichen Patterns in der Tabelle PATTERN anzulegen, halte ich eher für unschön...???
Wenn man Patterns mehrfach nutzt, kann das die Handhabung erschweren. Wenn die Erkennung bei einem Lieferanten mal nicht zufriedenstellend ist, wird man das entsprechende Pattern verbessern wollen. Falls das dann auch woanders genutzt wird, verschlechtert man möglicherweise das dort bisher gute Ergebnis. Also müsste man erst ein neues Pattern erstellen. Der Normalisierungsgedanke, der beim Datenbankentwurf sinnvoll ist, könnte hier eher stören.
PATTERN_SETS_PATTERN -> Zwischentabelle, sodass ein Lieferant mehrere PATTERNS nutzen kann
Das kann er doch ohnehin.:confused:
Meines Erachtes müsste man die PATTERN - Tabelle auch noch um die Spalte "languageCode" erweitern. Ein Lieferant (mit der gleichen Steuernummer) kann die Rechnung ja in Englisch, als auch in Deutsch ausliefern.
Ist das wirklich nötig? Einige rein strukturelle Pattern würden sprachunabhängig funktionieren. Und für die übrigen gestaltet man das Pattern entweder mehrsprachig oder legt pro Sprache ein eigenes an. Es matcht ja ohnehin nur auf sein Muster und muss gar nicht wissen, ob das dann deutsch oder englisch ist. Man kann für denselben Lieferanten auch zwei Pattern-Sets anlegen und in den Identifikations-RegEx eben noch ein geeignetes Wort der jeweiligen Sprache einbauen, so dass nur ein Set matcht. Oder man lässt einfach beide matchen und für manche Werte wird nur nur eines Ergebnisse liefern und für andere Werte tun es beide. Das schadet ja alles überhaupt nicht.
Durch eine Methode oder manuelle Auswahl des Users, wird dann eben der Sprachcode ermittelt.
Wenn die Rechnung in Englisch ist, dann werden eben PATTERN 1-2 angewandt, wenn in Deutsch, dann PATTERN 3-4. (PATTERN_SET_FK) ist jeweils der gleiche.
Wie gesagt, sehe ich diese Notwendigkeit für die eigentliche Erkennung nicht, aber wenn man den Sprachcode für andere Zwecke dennoch benötigt, könnte man ihn auch über Pattern ermitteln lassen, sofern man die weiter oben erwähnte Ersetzungsfunktion einbaut. Das wäre ein Beispielfall dafür, nicht nur ein sondern alle Pattern-Sets ausführen zu lassen. Man definiert ein Pattern-Set, das auf jedes Dokument matcht und ein Pattern pro Sprache enthält, welches den Sprachcode liefert. Das individuelle Pattern-Set des Lieferanten matcht ebenfalls und liefert die übrigen Daten. So kann man ganz gut ein Baukastensystem aufbauen, bei dem global funktionierende Erkennungen nicht in jedes Pattern-Set integriert werden müssen.
 

beta20

Top Contributor
Ok, danke.

Erkennung Typ der Rechnung (Kategorie):
-> Wie willst du das über ein Pattern lösen?
-> Beispiel:
a) Du kaufst bei Amazon einen Stuhl und buchst das als Büromaterial
b) Morgen kaufst du bei Amazon einen Telefon und buchst das unter Telefon

-> Würdest du hier dann wiederum Patterns anlegen, damit die einzelnen Positionsarten ermittelt werden?


Hm, ich weiß nicht - halte ich eher für unschön, in der Tabelle PATTERNS mehrmals das gleiche Pattern zu speichern, wenn unterschiedliche Lieferanten das gleiche Pattern nutzen:

ID PATTERN_SET REGEX
1 1 (\b\w{24}\b)
2 2 (\b\w{24}\b)

In der PATTERN - Tabelle würde ich wirklich nur die verfügbaren PATTERNS speichern, die es tatsächlich gibt, also genau 1x
Sofern kein Treffer eines PATTERN_SET gefunden wird, könnte ich ja die einzelnen PATTERN von der Tabelle PATTERN durchgehen, ggf. matched dann das ein oder andere aber eben nicht alle von einem PATTERN_SET

Ich kann ja über 1000 Lieferanten (also 1000 PATTERN_SETS) haben, wenn jeder von diesen mehrmals von der Syntax das gleiche PATTERN nutzt (also der Eintrag kommt mehrmals in der PATTERN Tabelle vor), ob das so sinnvoll ist?
Kann man mit Sicherheit so machen. Den Vorteil, den ich aber sehe ist, wenn ich keinen Treffer zu einem PATTERN_SET finde, muss ich nicht 1000 x X Patterns durchgehen, sondern nur die Einträge, die in PATTERN sind.
 

Meniskusschaden

Top Contributor
Was denn für PATTERN jetzt aufeinmal, wovon redet ihr, worum geht es?:confused:
Im Kontext dieses Threads ist ein Pattern (ungefähr) ein regulärer Ausdruck, der den Zweck hat, den Wert für einen bestimmten Schlüssel (z.B. Rechnungsnummer) aus einer Rechnung eines bestimmten Lieferanten zu extrahieren. Und ein Pattern-Set ist eine Sammlung von Pattern, die die Werte für alle Schlüssel aus einer Rechnung eines bestimmten Lieferanten ermitteln sollen. Wenn man das wirklich programmiert, sollte man vielleicht bessere Namen finden.;)
Erkennung Typ der Rechnung (Kategorie):
-> Wie willst du das über ein Pattern lösen?
-> Beispiel:
a) Du kaufst bei Amazon einen Stuhl und buchst das als Büromaterial
b) Morgen kaufst du bei Amazon einen Telefon und buchst das unter Telefon

-> Würdest du hier dann wiederum Patterns anlegen, damit die einzelnen Positionsarten ermittelt werden?
Ursprünglich war die Kategorie doch eher ein grobes Branchenkennzeichen, bei dem man davon ausgehen konnte, dass es bei demselben Lieferanten nahezu konstant ist (Hotel, Hoster). Da hätte man im Set des Lieferanten entweder ein Pattern mit einem konstanten Wert oder mehrere Pattern mit Bezeichnungen angelegt.
Das neue Beispiel (Stuhl, Telefon) ist jetzt aber viel spezifischer. Deine ursprüngliche Anforderung war kaum mehr, als den Rechnungsbetrag zu ermitteln, was man mal so eben aus der hohlen Hand umsetzen kann. Jetzt sind wir plötzlich bei einer Rechnungspositionserkennung. Ich hatte schon in einem meiner ersten Beiträge angedeutet, dass das eine ganz andere Grössenordnung ist. Das wird dann schon ein Projekt, bei dem man auch eine vernünftige Analyse machen muss. So etwas würde ich aber nur anfangen, wenn positionsweise Daten aus Bestellungen und Wareneingangen der Warenwirtschaft zur Verfügung stehen. Sonst kann man das, was man aus der Dokumentenerkennung bekommt, sowieso nicht sinnvoll weiter verarbeiten.
In der PATTERN - Tabelle würde ich wirklich nur die verfügbaren PATTERNS speichern, die es tatsächlich gibt, also genau 1x
Sofern kein Treffer eines PATTERN_SET gefunden wird, könnte ich ja die einzelnen PATTERN von der Tabelle PATTERN durchgehen, ggf. matched dann das ein oder andere aber eben nicht alle von einem PATTERN_SET
Die würden bestimmt hier und da matchen. Wenn sie aber für einen anderen Lieferanten entwickelt wurden, bekommt man da aber sicher auch mal beispielsweise ein Auftragsdatum zurück, wenn man eigentlich ein Rechnungsdatum haben will. Die Lieferanten stimmen sich ja nicht untereinander ab, in welcher Reihenfolge sie solche Angaben auf der Rechnung machen.
Außerdem würden wahrscheinlich Pattern-Leichen entstehen, weil man bei Anpassungen sicherheitshalber ein neues Pattern erstellt, obwohl es vielleicht ausschließlich für den Lieferanten, den man gerade verbessern will, benutzt wird und gefahrlos geändert werden könnte. Ich glaube, es ist viel einfacher, bei einem neuen Lieferanten irgendein Pattern-Set zu kopieren und da die RegEx rein zu kopieren, die man im RegExp-Tester entwickelt.
Die Variationen der OCR können so vielfältig sein, dass es ohnehin schwierig wäre, vordefinierte Pattern vernünfttig zu benennen, damit man sie für eine Wiederverwendung überhaupt findet. Man braucht unterschiedliche Pattern ja nicht nur aufgrund verschieden strukturierter Rechnungen, sondern auch zur Kompensation von OCR-Fehlern. Da muß man manchmal trotz eigentlich gleicher Struktur dennoch individuelle Umwege nehmen.
Den Vorteil, den ich aber sehe ist, wenn ich keinen Treffer zu einem PATTERN_SET finde, muss ich nicht 1000 x X Patterns durchgehen, sondern nur die Einträge, die in PATTERN sind.
Wie bereits im vorigen Abschnitt beschrieben, würde ich das nicht machen, denn ich hätte lieber keinen Treffer, als einen falschen.
 

X2X

Mitglied
Wir verwenden dazu den X2X-Software-Roboter von triple-s (www.sss.de).

Das grundsätzliche Vergehen ist genau wie hier diskutiert. Es gibt eine Datei in der zu jedem Lieferanten Erkennungsmerkmale wie zum Beispiel die Umsatzsteuernummer hinterlegt sind. Der Software-Roboter entscheidet damit welches Rechnungstemplate (Stucture-TYPE) verwendet werden soll. In zweiten Schritt wir das Template verwendet um alle Daten aus der Rechnung auszulesen.

Das Rechnungstemplate (TYPE) legt der Anwender mit einer speziellen aber einfachen Hochsprache fest. (Hat nichts mit RegExp zu tun). Der Clou ist jetzt noch, dass der Anwender auch noch selbst festlegen kann, in welchem Format er die gelesen Daten zur Weiterverarbeitung ablegen will. Das kann ein Standardformat wie Json oder XML sein oder aber auch ein ganz individuelles Hausformat. Dafür stehen andere Templates (sogenannte PATTERN) zu Verfügung.

Es ist natürlich klar, dass da aus den TYPEs zur Laufzeit irgendwie ein Parser und aus den Pattern zu Laufzeit irgendwie ein Generator gebaut wird.
 

beta20

Top Contributor
also ich hatte mich damit weiterbefasst und bin dann irgendwann zu Machine Learning gekommen.
Sprich es kommen immer wieder neue Rechnungsformate dazu, sodass das System dazu lernen muss.

Weiter habe ich es dann aber nicht verfolgt, da es nicht Prio1 ist. Aber wenn in naher Zukunft benötige ich es...
 

TM69

Bekanntes Mitglied
Ok, danke.

Ich brauche den Scan nicht als Word / Excelfile.
Ich will lediglich aus dem Scan / Datei die verschiedenen Informationen aus einer Rechnung herausbekommen (Betrag, Datum...).
Was ich mich nun allerdings frage, lohnt sich der Aufwand überhaupt das selbst zu programmieren?
Es gibt doch sicherlicht Dienste mittlerweile, die das für einen übernehmen können, die man dann mit einer REST API ansprechen kann? Oder sieht ihr das anderst?
Es lohnt sich nicht. Denn echte Bürokopierer / Scanner machen dieses von Hause. Allerdings sei hier vorsichtig, wie folgender Beitrag zeigt:

Ansonsten gibt es einige OCR SDK sowohl OpenSource als auch ClosedSource z.B. Abby
https://www.abbyy.com/de-de/ocr-sdk/?gclid=EAIaIQobChMIod3DqtKc5wIVxOJ3Ch1G9wuTEAAYASAAEgJ_IPD_BwE
 

X2X

Mitglied
also ich hatte mich damit weiterbefasst und bin dann irgendwann zu Machine Learning gekommen.
Sprich es kommen immer wieder neue Rechnungsformate dazu, sodass das System dazu lernen muss.

Weiter habe ich es dann aber nicht verfolgt, da es nicht Prio1 ist. Aber wenn in naher Zukunft benötige ich es...
Wenn man die Sammlung der Templates als das Wissen des Software-Roboters betrachtet, dann ist es Machine-Learning, weil ja immer wieder neue Lieferanten/Templates dazukommen oder auch mal erweitert werden müssen.
 

TM69

Bekanntes Mitglied
Also man legt ein Dokument in den Scanner und der gibt dann nur mit Bordmitteln strukturiert Lieferantennamen, Rechnungsnummer, Rechnungsdatum, Rechnungsbetrag etc. zurück? So ein Gerät hätte ich gerne. Wo gibt's die denn?;)
Okay sry falsch ausgedrückt, ich wollte damit sagen das professionelle Geräte SDKs bieten.:D:D Standisierte Formular können z.B. durch DMS mit OCR erreichen, soweit mir bekannt kann dieses z.B. Alfresco.
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
D MacOS: PDF erstellen geht nicht Java Basics - Anfänger-Themen 1
P Netbeans installation geht nicht Java Basics - Anfänger-Themen 26
Ostkreuz wie geht der catch? Java Basics - Anfänger-Themen 3
A Methoden Guten Tag , ich wollte so machen dass wenn meine frog an eine fly/bee geht dann an meine Tafel geht der zahl +1 hoch. Java Basics - Anfänger-Themen 2
S IntelliJ geht alle Klassen durch Java Basics - Anfänger-Themen 9
B Explizit Array definieren geht nicht? Java Basics - Anfänger-Themen 14
Say Stelle in Code herausfinden, wie geht man vor? Java Basics - Anfänger-Themen 12
berserkerdq2 Geht collections.sort bei allen? Linkedhashset, ArrayList, HashSet etc. Java Basics - Anfänger-Themen 4
P Installation JRE 8u321 startet, geht aber nicht weiter Java Basics - Anfänger-Themen 1
E Rekursiv Objekte erzeugen - geht das? Java Basics - Anfänger-Themen 2
E Pervasive PSQL insert funktion geht nicht Java Basics - Anfänger-Themen 9
U Warum kann ich die Methode in der ENUM Klasse nicht aufrufen? Und warum geht die Switch nicht? Java Basics - Anfänger-Themen 8
H Wie geht eigentlich Objektorientierung? Java Basics - Anfänger-Themen 14
M Methoden Wert einer Variable geht verloren? Java Basics - Anfänger-Themen 6
melisax Lower & Uppercase Beispielprogramm geht nicht Java Basics - Anfänger-Themen 3
MarcKKKK123 Wie geht das? Java Basics - Anfänger-Themen 1
B Static Attribute in einer Klasse, wie geht das? :O Java Basics - Anfänger-Themen 19
N methodenaufruf for each geht nicht Java Basics - Anfänger-Themen 2
O Methode in while-Schleife aufrufen geht nur beim ersten Mal Java Basics - Anfänger-Themen 2
W App geht live und dann? Java Basics - Anfänger-Themen 9
P Geht es vielleicht viel kürzer? Java Basics - Anfänger-Themen 7
S While-Schleife geht in Endlosschleife über, warum? Java Basics - Anfänger-Themen 6
B Interface List - Objekt übergeben? Einzelnes Objekt geht, aber Liste nicht? Java Basics - Anfänger-Themen 4
K Erste Schritte Programm geht aus Schleife, warum? Java Basics - Anfänger-Themen 2
S Geht das bei Java ? Java Basics - Anfänger-Themen 11
L Wie geht man bei mehreren Action Klassen vor? Java Basics - Anfänger-Themen 0
C unverständlicher Code Attribute ohne Datentyp, wie geht das? Java Basics - Anfänger-Themen 8
CptK Klassen KeyListner geht nicht Java Basics - Anfänger-Themen 7
L Klassen Objekt aus einer Warteschlange in eine andere übergeben, geht nicht? Java Basics - Anfänger-Themen 6
K Armstrong Programm geht nur bis 1000, aber nicht weiter Java Basics - Anfänger-Themen 2
M Nim-Spiel geht in den negativen Bereich Java Basics - Anfänger-Themen 1
amazinglife77 Input/Output Lesen/Schreiben Properties: in eclipse geht, als JAR nicht Java Basics - Anfänger-Themen 4
V Erste Schritte Warum geht meine continue Anweisung nicht? Java Basics - Anfänger-Themen 8
MR._FIRE_Flower String.split("(") geht nicht Java Basics - Anfänger-Themen 4
M Restbuchwert Berechnung geht nicht Java Basics - Anfänger-Themen 45
K Klassen Nachträglich ein Objekt einem anderen zuweisen, geht das? Java Basics - Anfänger-Themen 2
S int addieren geht nicht Java Basics - Anfänger-Themen 13
L system.print.out geht nicht Java Basics - Anfänger-Themen 11
M Referenz geht bei Zwischenspeichern verloren (ArrayList) Java Basics - Anfänger-Themen 4
S Komma geht beim Schreiben ins csv verloren. Java Basics - Anfänger-Themen 6
M Arrays einspeichern geht nicht Java Basics - Anfänger-Themen 21
J BlueJ und import-Anweisungen, wie geht das? Java Basics - Anfänger-Themen 4
J Geht mit Java überhaupt was? Java Basics - Anfänger-Themen 13
J Debuggen - wie geht das? Java Basics - Anfänger-Themen 6
I erstelle Vorschaubild mit der lib PDF-Renderer und möchte danach Dateiname ändern -> geht aber nicht Java Basics - Anfänger-Themen 0
J Ausführen geht nicht Java Basics - Anfänger-Themen 19
G System.out.printf geht nicht Java Basics - Anfänger-Themen 6
E Erste Schritte [Noob] Warum geht meine For-Schleife nicht? Java Basics - Anfänger-Themen 2
I Java Code so gut es geht Kommentieren Java Basics - Anfänger-Themen 4
S Button "Berechnen" geht nicht Java Basics - Anfänger-Themen 3
B Compiler-Fehler Ein Java-Eclipse-Anfänger geht auf Reisen... Java Basics - Anfänger-Themen 10
K JUnit: Objekte von eigenen Klassen vergleichen...geht nicht Java Basics - Anfänger-Themen 5
T fianl array geht nicht... Java Basics - Anfänger-Themen 2
O if and else geht nur manchmal Java Basics - Anfänger-Themen 17
B Nichts geht mehr Java Basics - Anfänger-Themen 10
D Java geht auf windows 64 bit nicht. Java Basics - Anfänger-Themen 5
V Einfacher vergleich von Arrays geht schief Java Basics - Anfänger-Themen 2
T sample.war geht nicht... Java Basics - Anfänger-Themen 1
Thallius Klassen aus Classname programmatisch erzeugen. Wie geht das in java? Java Basics - Anfänger-Themen 5
C Datentypumwandlung geht nicht Java Basics - Anfänger-Themen 5
U kompilieren geht nicht wg. Formatierung wahrscheinlich Java Basics - Anfänger-Themen 7
G While schleife mit 2 Bedingungen geht nicht! Java Basics - Anfänger-Themen 15
S Methoden Rückgabewert einer Methode als Parameter an eine andere Methode übergeben, geht das? Java Basics - Anfänger-Themen 5
L Das erste Mal GridBagLayout - wie geht das? Java Basics - Anfänger-Themen 5
O Jar Datei erstellen geht nicht. Java Basics - Anfänger-Themen 4
O (.+?) --> $1 geht nicht Java Basics - Anfänger-Themen 5
V relativer Pfad geht nicht, absolut schon? Java Basics - Anfänger-Themen 3
R Java JDK/ Kompiler geht nicht Java Basics - Anfänger-Themen 4
H Geht dieser Code noch einfacher (try catch finally) Java Basics - Anfänger-Themen 7
P Geht dieser Code noch einfacher? Java Basics - Anfänger-Themen 16
J Warum geht int und String nicht? Java Basics - Anfänger-Themen 18
J repaint() geht gar nicht; GUI aktualisieren Java Basics - Anfänger-Themen 10
N ArrayList geht nicht Java Basics - Anfänger-Themen 8
B Erste Schritte Listing aus Buch - wie geht das? Java Basics - Anfänger-Themen 6
K Datentypen Kurzform Addition geht, Langform scheitert am Typen Java Basics - Anfänger-Themen 6
R Einfacher Timer geht nicht Java Basics - Anfänger-Themen 7
J Anzeige erneuern, wie geht das? Java Basics - Anfänger-Themen 6
D Compiler-Fehler ANT-Script geht nicht Java Basics - Anfänger-Themen 6
A Android Datenbank gaaanz einfaches Insert geht nicht - warum? Java Basics - Anfänger-Themen 4
N JAVA Installation - Umgebungsvariable geht nicht. Java Basics - Anfänger-Themen 3
K Aus JFrame-Fenster SuM-Fenster öffnen geht nicht! Java Basics - Anfänger-Themen 8
L Jarfiles packen, wie geht's genau? Java Basics - Anfänger-Themen 12
K Erste Schritte Progressbar geht nicht Java Basics - Anfänger-Themen 5
H Ein alternativer Konstruktor geht nicht Java Basics - Anfänger-Themen 3
B Std-Serialisierung - Speichern/Laden geht nur auf einem Rechner Java Basics - Anfänger-Themen 17
F Geht in alle Case rein, warum?? Java Basics - Anfänger-Themen 12
El_Lobo Methoden Zu viele Getter- und Settermethoden - geht das einfacher? Java Basics - Anfänger-Themen 3
P quickSort eines Objekt-Arrays geht nicht! Java Basics - Anfänger-Themen 11
M if then else geht nicht Java Basics - Anfänger-Themen 10
N Methoden mehrere replace hintereinander geht nicht ? Java Basics - Anfänger-Themen 2
Maxim6394 KeyListener geht nicht Java Basics - Anfänger-Themen 15
C Erste Schritte switch Anweisung geht nicht Java Basics - Anfänger-Themen 3
N geht oder geht nicht? Java Basics - Anfänger-Themen 24
E bo wie geht das denn? Java Basics - Anfänger-Themen 8
Z Anfügen an Arraylist geht nicht Java Basics - Anfänger-Themen 3
M Unterverzeichnisse löschen geht nicht. Java Basics - Anfänger-Themen 3
T Methoden Array kopieren: Wie geht das? Java Basics - Anfänger-Themen 20
M If Abfrage geht nicht Java Basics - Anfänger-Themen 2
0 file.delete() geht nicht Java Basics - Anfänger-Themen 23
0 String split und replace geht nicht Java Basics - Anfänger-Themen 17

Ähnliche Java Themen

Neue Themen


Oben