Banktransacties importeren

Scanner/parser

Het is de taak van de scanner/parser om het invoer bestand te ontleden en zodanig te bewerken dat er gegevens uit gehaald worden die in de database gestopt kunnen worden. Omdat ABNAMRO-bank, zeer recent een 'export'-functie aan Internetbankieren heeft toegevoegd, ga ik uit van het bestand formaat dat je verkrijgt als je je transacties exporteert naar een TXT-bestand. De bestanden worden door ABNAMRO Internetbankieren opgeslagen als b.v. TXT191002112122.TAB.

Het formaat van TXT191002112122.TAB ziet er als volgt uit:

rekening-nummer val boek-datum begin saldo eind saldo rente-datum bedrag omschrijving
123456789 EUR 20021019 123,34 -200, 20021220 -12,34 pin-opname etc.

Preciezer gezegd: het bestand bestaat uit regels waarbij elke regel voldoet aan de opbouw zoals in de 2e rij van bovenstaande tabel, het scheiding steken tussen de kolommen is het TAB-teken. De kop van de tabel staat niet in het bestand. Bestuderen we het bestand nader, dan onderkennen we vier verschillende typen woorden in het bestand:

  1. INTEGER: het rekeningnummer, de boek- en rentedata zijn gecodeerd als gehele getallen

  2. EUR: een vaste string "EUR" geeft de gebruikte valuta aan

  3. FLOAT: het begin, eindsaldo en bedrag van de transactie worden als gebroken getallen gecodeerd. Altijd staat er een komma in dit getal

  4. STRING: de omschrijving bestaat uit afdrukbare tekens.

We gaan het programma Flex nu zo sturen dat het een scanner genereert die precies bovenstaande woorden uit het bestand filtert. Dit kan met de volgende stuur bestand:

%%
[0-9]+/\t+ { printf("INT: %s\n", yytext); }
EUR"/\t+ { printf("EUR: %s\n", yytext); }
[-]?[0-9]+,[0-9]*/\t+ { printf("FLOAT: %s\n", yytext); }
[[:print:] ]+ { printf("STR: %s\n", yytext); }
\t |
\r |
\n { }
. { printf("Onbekend teken: 0x%x\n", yytext[0]); }
%%
int main(void)
{
  return yylex();
}

Sla het bovenstaand op in het bestand fnlx.l en genereer het programma fn door de volgende commando's in de shell in te geven:

$ flex fnlx.l
$ gcc -o fn lex.yy.c -lfl

en test het, door in tikken

$ fn < TXT191002112122.TAB

waarbij TXT191002112122.TAB een bestand is dat je vanaf de ABNAMRO site hebt geëxporteerd. Als alles goed is zul je de inhoud van TXT191002112122.TAB zien, voorafgegaan door de woorden INT, FLOAT, STR of EUR. Dit is het bewijs dat de woorden correct herkend werden.

Een eerste deel van het werk is af, nu moeten we nog het bestandsformaat formeel vastleggen, door een zogenaamde parser te bouwen. Het is de taak van de parser om de invoer te controleren ten opzichte van de vastgelegd syntax. Voldoet de invoer niet dan zal een foutmelding gegenereerd worden, die in zijn minimale vorm bestaat uit de melding "syntax error". Bestuderen we bovenstaande opbouw van het bestand nogmaals dan is de syntax hiervan, te beschrijven als:

  1. het bestand bestaat uit één of meer regels
  2. elke regel bestaat uit een INT, gevolgd door EUR, gevolgd door INT, etc.

In het stuur bestand voor Yacc ziet dit er als volgt uit:

%token INT
%token STR
%token FLOAT
%token EUR
%%
bestand: regels
;

regels: regels regel
| regel
;

regel: INT EUR INT FLOAT FLOAT INT FLOAT STR
;

void yyerror(char *ptr)
{
  extern int yylineno;
  printf("Syntax error at line %d\n", yylineno);
}

int main(void)
{
  return yyparse();
}

Sla bovenstaand op in het bestand fnpr.y en genereer de parser met de volgende commando's:

 
$ yacc -d fnpr.y
$ gcc -c y.tab.c

Pas nu fnlx.l als volgt aan:

%{
#include "y.tab.h"
%}
%option yylineno
%%
[0-9]+/\t+ { return INT; }
"EUR"/\t+ { return EUR; }
[-]?[0-9]+,[0-9]*/\t+ { return FLOAT; }
[[:print:] ]+ { return STR; }
\t |
\r |
\n { }
. { printf("Onbekend teken: 0x%x\n", yytext[0]); }
%%

Genereer de scanner opnieuw en genereer het programma fn met de volgende commando's:

$ flex fnlx.l
$ gcc -c lex.yy.c
$ gcc -o fn y.tab.o lex.yy.o -lfl

en test het vervolgens, door in tikken

$ fn < TXT191002112122.TAB

Als alles goed is zul je nu niets te zien krijgen! Dit is het bewijs dat de woorden correct herkend zijn. Pas nu TXT191002112122.TAB aan, vervang b.v het woord "EUR" door "HFL", of iets anders, en herhaal de test. De magische melding "syntax error" verschijnt nu, en inderdaad het bestand voldoet nu niet aan de opgegeven syntax. Door met de inhoud van TXT191002112122.TAB te spelen kun je nagaan hoe goed de parser de syntax controleert.

Merk op dat we slechts 42 regels broncode, in fnpr.y en fnlx.l, nodig hebben gehad om het skelet van de scanner/parser te maken.

$Id: hfst31.html,v 1.19 2016/07/29 18:37:16 luc Exp $Valid XHTML 1.0! Valid CSS 1.0!