Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[PHP][RegEx] Sepa regel scheiden

Pagina: 1
Acties:

  • MichielioZ
  • Registratie: Augustus 2001
  • Laatst online: 11-11 20:46
Ik heb een klein bedrijfje en doe een aantal administratieve zaken op een locale webserver in PHP/MySQL.
Nu heb ik altijd mijn bankafschriften van ING ingevoerd d.m.v. een ASCII bestand en dat ging tot nog toe altijd goed. Met de komst van SEPA (en dus IBAN en BIC) wil ik graag m'n scriptje aanpassen om met een MT940 bestand te werken. Ik loop echter tegen een (wellicht onoverkomelijk) regex probleem aan...
Een afschrift in MT940 slaat de meeste informatie op in de 'omschrijvingsregel' (:86: veld), dit ziet er als volgt uit:
<rekening> <iban> <bic> <naam> <end-to-end-id> <omschrijving>
Het conflict zit hem in de overloop van naam naar 'end-to-end-id' (eteID) naar omschrijving.
Alle drie de velden kunnen spaties bevatten en zover ik kan vinden kunnen ze uit alle tekens van de SWIFT karakter set bestaan (zie onder voor de regex).
Het <naam>-veld heeft een maximale lengte van 70 karakters.
Tot nu toe heb ik alleen eteID's gezien met [0-9]+ formaat of als waarde 'NOTPROVIDED', maar ik dacht dat ook andere karakters mogelijk zijn. Het veld kan 1 tot 35 karakters bevatten.
Het <omschrijving>-veld heeft een maximale lengte van 140 karakters.

Mijn huidige (foutieve) plan van aanpak is:
PHP:
1
2
3
4
5
6
7
8
$swift = '[a-zA-Z0-9\/\-\?\(\)\.\,\+\'\{\}\: ]'; // SWIFT karakters
$ete   = '[0-9]{1,35}|NOTPROVIDED';
$name  = '[a-zA-Z\/\-\?\(\)\.\,\+\'\{\}\: ]'; // subset van SWIFT (zonder getallen)

if (preg_match('/(alle andere velden)('.$name.'{1,70}) ('.$ete.') (.*)/', $info, $matches)) { }
// Eerder geprobeerd met:
if (preg_match('/(alle andere velden)('.$swift.'{1,70}) ('.$ete.') (.*)/', $info, $matches)) { }
// maar toen ging het iets te vaak fout...


Op zich werkt het, ware het niet dat ik een subset voor de <naam> gebruik en dus geen namen met getallen kan uitlezen.
Heeft iemand hier een betere ingeving dan ik ? (vast wel) 8)

[ Voor 6% gewijzigd door MichielioZ op 29-11-2013 19:16 ]

Iedereen wil terug naar de natuur, maar niemand wil lopend...


  • frG
  • Registratie: Augustus 2004
  • Laatst online: 20-11 20:03

frG

Is het niet handiger om al een bestaande parser te gebruiken hiervoor?

Zoiets bijvoorbeeld: https://github.com/sandermarechal/jejik-mt940

  • MichielioZ
  • Registratie: Augustus 2001
  • Laatst online: 11-11 20:46
frG schreef op vrijdag 29 november 2013 @ 19:16:
Is het niet handiger om al een bestaande parser te gebruiken hiervoor?

Zoiets bijvoorbeeld: https://github.com/sandermarechal/jejik-mt940
Dat zou erg handig zijn inderdaad, maar ik heb al heel github afgestruind (inclusief die jij noemt) en heb er geen gevonden die met de (huidige) SEPA implementaties werkt...

edit:
De link die je gaf ondersteund wel de Rabobank implementatie, maar die is helaas voor mij heel anders dan de ING implementatie...

[ Voor 14% gewijzigd door MichielioZ op 29-11-2013 19:22 ]

Iedereen wil terug naar de natuur, maar niemand wil lopend...


  • DJMaze
  • Registratie: Juni 2002
  • Niet online
IBAN nummers zijn verschillend.
Even een cut/paste van mijn validatie class
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?php
/*  Poodle WCMS, Copyright (c) MH X Solutions since 2010. All rights reserved.

    The contents of this file are subject to the terms of the
    Common Development and Distribution License, Version 1.0 only
    (the "License").  You may not use this file except in compliance
    with the License.

    en.wikipedia.org/wiki/International_Bank_Account_Number

    \Poodle\Validate\IBAN::verify('IBAN number')
*/

namespace Poodle\Validate;

abstract class IBAN
{

    protected static $regexByCountry = array(
        'AA' => '([A-Z0-9]{12})',
        'AD' => '([0-9]{4})([0-9]{4})([A-Za-z0-9]{12})',
        'AE' => '([0-9]{3})([0-9]{16})',
        'AL' => '([0-9]{8})([A-Za-z0-9]{16})',
        'AT' => '([0-9]{5})([0-9]{11})',
        'AZ' => '([A-Z]{4})([A-Za-z0-9]{20})',
        'BA' => '([0-9]{3})([0-9]{3})([0-9]{8})([0-9]{2})',
        'BE' => '([0-9]{3})([0-9]{7})([0-9]{2})',
        'BG' => '([A-Z]{4})([0-9]{4})([0-9]{2})([A-Za-z0-9]{8})',
        'BH' => '([A-Z]{4})([A-Za-z0-9]{14})',
        'BL' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'BR' => '([0-9]{8})([0-9]{5})([0-9]{10})([A-Z]{1})([A-Za-z0-9]{1})',
        'CH' => '([0-9]{5})([A-Za-z0-9]{12})',
        'CR' => '([0-9]{3})([0-9]{14})',
        'CY' => '([0-9]{3})([0-9]{5})([A-Za-z0-9]{16})',
        'CZ' => '([0-9]{4})([0-9]{6})([0-9]{10})',
        'DE' => '([0-9]{8})([0-9]{10})',
        'DK' => '([0-9]{4})([0-9]{9})([0-9]{1})',
        'DO' => '([A-Za-z0-9]{4})([0-9]{20})',
        'EE' => '([0-9]{2})([0-9]{2})([0-9]{11})([0-9]{1})',
        'ES' => '([0-9]{4})([0-9]{4})([0-9]{1})([0-9]{1})([0-9]{10})',
        'FI' => '([0-9]{6})([0-9]{7})([0-9]{1})',
        'FO' => '([0-9]{4})([0-9]{9})([0-9]{1})',
        'FR' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'GB' => '([A-Z]{4})([0-9]{6})([0-9]{8})',
        'GE' => '([A-Z]{2})([0-9]{16})',
        'GF' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'GI' => '([A-Z]{4})([A-Za-z0-9]{15})',
        'GL' => '([0-9]{4})([0-9]{9})([0-9]{1})',
        'GP' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'GR' => '([0-9]{3})([0-9]{4})([A-Za-z0-9]{16})',
        'GT' => '([A-Za-z0-9]{4})([A-Za-z0-9]{20})',
        'HR' => '([0-9]{7})([0-9]{10})',
        'HU' => '([0-9]{3})([0-9]{4})([0-9]{1})([0-9]{15})([0-9]{1})',
        'IE' => '([A-Z]{4})([0-9]{6})([0-9]{8})',
        'IL' => '([0-9]{3})([0-9]{3})([0-9]{13})',
        'IS' => '([0-9]{4})([0-9]{2})([0-9]{6})([0-9]{10})',
        'IT' => '([A-Z]{1})([0-9]{5})([0-9]{5})([A-Za-z0-9]{12})',
        'KW' => '([A-Z]{4})([0-9]{22})',
        'KZ' => '([0-9]{3})([A-Za-z0-9]{13})',
        'LB' => '([0-9]{4})([A-Za-z0-9]{20})',
        'LI' => '([0-9]{5})([A-Za-z0-9]{12})',
        'LT' => '([0-9]{5})([0-9]{11})',
        'LU' => '([0-9]{3})([A-Za-z0-9]{13})',
        'LV' => '([A-Z]{4})([A-Za-z0-9]{13})',
        'MC' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'MD' => '([A-Za-z0-9]{20})',
        'ME' => '([0-9]{3})([0-9]{13})([0-9]{2})',
        'MF' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'MK' => '([0-9]{3})([A-Za-z0-9]{10})([0-9]{2})',
        'MQ' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'MR' => '([0-9]{5})([0-9]{5})([0-9]{11})([0-9]{2})',
        'MT' => '([A-Z]{4})([0-9]{5})([A-Za-z0-9]{18})',
        'MU' => '([A-Z]{4})([0-9]{2})([0-9]{2})([0-9]{12})([0-9]{3})([A-Z]{3})',
        'NC' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'NL' => '([A-Z]{4})([0-9]{10})',
        'NO' => '([0-9]{4})([0-9]{6})([0-9]{1})',
        'PF' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'PK' => '([A-Z]{4})([A-Za-z0-9]{16})',
        'PL' => '([0-9]{8})([0-9]{1,16})',
        'PM' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'PS' => '([A-Z]{4})([A-Za-z0-9]{21})',
        'PT' => '([0-9]{4})([0-9]{4})([0-9]{11})([0-9]{2})',
        'RE' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'RO' => '([A-Z]{4})([A-Za-z0-9]{16})',
        'RS' => '([0-9]{3})([0-9]{13})([0-9]{2})',
        'SA' => '([0-9]{2})([A-Za-z0-9]{18})',
        'SE' => '([0-9]{3})([0-9]{16})([0-9]{1})',
        'SI' => '([0-9]{5})([0-9]{8})([0-9]{2})',
        'SK' => '([0-9]{4})([0-9]{6})([0-9]{10})',
        'SM' => '([A-Z]{1})([0-9]{5})([0-9]{5})([A-Za-z0-9]{12})',
        'TF' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'TN' => '([0-9]{2})([0-9]{3})([0-9]{13})([0-9]{2})',
        'TR' => '([0-9]{5})([A-Za-z0-9]{1})([A-Za-z0-9]{16})',
        'VG' => '([A-Z]{4})([0-9]{16})',
        'WF' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
        'YT' => '([0-9]{5})([0-9]{5})([A-Za-z0-9]{11})([0-9]{2})',
    );

    protected static function mod97_10($number)
    {
        if (function_exists('gmp_intval')) {
            return gmp_intval(gmp_mod(gmp_init($number, 10), '97'));
        }
//      return \Poodle\Math::mod($number, '97');
        if (function_exists('bcmod')) {
            return (int)bcmod($number, '97');
        }

        $len = strlen(PHP_INT_MAX)-1;
        $mod = '';
        do {
            $number = $mod.$number;
            $mod = substr($number, 0, $len) % 97;
            $number = substr($number, $len);
        } while (strlen($number));
        return $mod;
    }

    public static function verify($iban)
    {
        $iban = preg_replace('/[^A-Z0-9]/','',strtoupper($iban));

        if (!preg_match('/^([A-Z]{2})([0-9]{2})(.+)$/D', $iban, $m)) {
            return false;
        }

        if (!isset(self::$regexByCountry[$m[1]])) {
            return true;
        }

        if (!preg_match('/^'.self::$regexByCountry[$m[1]].'$/D', $m[3])) {
            return false;
        }

        # move first 4 chars (countrycode and checksum) to the end of the string
        # Character substitution required for IBAN MOD97-10 checksum validation/generation
        $number = str_replace(range('A','Z'), range(10,35), $m[3].$m[1].$m[2]);
        return 1 === self::mod97_10($number);
    }

}

Maak je niet druk, dat doet de compressor maar


  • MichielioZ
  • Registratie: Augustus 2001
  • Laatst online: 11-11 20:46
Bedankt, maar de IBAN geeft geen problemen, ik heb daar een heel algemene regex op zitten die in de context van de hele 'regel' goed werkt. (en verificatie laat ik lekker aan de bank zelf over ;-))
Er moet een manier zijn om die 3 velden uit elkaar te trekken, maar welke slimme vogel bij ING heeft verzonnen dat ze de velden scheiden d.m.v. een spatie... zucht.

Iedereen wil terug naar de natuur, maar niemand wil lopend...


  • pedorus
  • Registratie: Januari 2008
  • Niet online
Ik mis wat voorbeeldregels van de input die aangeven waarom het mis gaat, dus dan wordt het lastig om je te helpen. Het lijkt me niet handig als we die van onze eigen bank moeten gaan halen ;) Ik neem aan dat de end-to-end-id geen spaties kan bevatten, en dat de bank geen ongeldige bestanden stuurt, dus [^ ]* zou al moeten werken. Heb je een voorbeeld met een ete-id met spaties?

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


  • _js_
  • Registratie: Oktober 2002
  • Laatst online: 25-10 14:28
pedorus schreef op zaterdag 30 november 2013 @ 10:26:
Het lijkt me niet handig als we die van onze eigen bank moeten gaan halen ;)
Elke bank heeft z'n eigen variant van MT940, vooral veld 86, dus van je eigen bank halen zou toch in veel gevallen niet nuttig zijn.

Volgens mij heeft ING dat formaat gewoon niet doordacht en kun je er eigenlijk niets mee, of misschien kun je veel eteid formaten gaan verzamelen en die per stuk gaan herkennen.

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
MichielioZ schreef op vrijdag 29 november 2013 @ 20:33:
Bedankt, maar de IBAN geeft geen problemen, ik heb daar een heel algemene regex op zitten die in de context van de hele 'regel' goed werkt. (en verificatie laat ik lekker aan de bank zelf over ;-))
Er moet een manier zijn om die 3 velden uit elkaar te trekken, maar welke slimme vogel bij ING heeft verzonnen dat ze de velden scheiden d.m.v. een spatie... zucht.
Het was ook meer als hint.
In die code zit veel info en regex.

Probeer dit eens
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
/**
 * ING MT940 regel voorbeelden:
 * :86:0123456789 NL69INGB0123456789 INGBNL2A J. Janssen
 * :86:0123456789 Europese Incasso doorlopend NL69INGB0123456789 INGBNL2A J. Jansen NL32ZZZ999999991234 MND-120123 20120501P01234785 CONTRIB
 * :86:0675432198 J. JANSSEN AMSTERDAM KN:3300169406045025
 * http://www.ing.nl/zakelijk/internetbankieren/bestandsformaten/
 */
if (preg_match('/^:86:(?P<rekening>.+)'
    . '\s+(?P<iban>[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30})'
    . '\s+(?P<bic>[A-Z]{6}[0-9]{2}[A-Z0-9]{2,5})'
    . '\s+(?P<ete>[A-Z0-9]+)'
    . '\s+(?P<omschrijving>.*)$/D', $info, $matches)
{
    print_r($matches);
}

[ Voor 18% gewijzigd door DJMaze op 30-11-2013 18:50 . Reden: Beter leesbaar gemaakt ]

Maak je niet druk, dat doet de compressor maar


  • MichielioZ
  • Registratie: Augustus 2001
  • Laatst online: 11-11 20:46
Dank je DJMaze, maar helaas mis je 1 (belangrijk) veld, de naam...
Mijn conclusie tot nu toe is dat het gewoon niet kan.
Rekeniningnummer, iban, bic is vrij gemakkelijk eruit te halen, maar dan komt het (in mijn ogen onmogelijke) gedeelte. Het resterende gedeelte is namelijk: 'naam' (SWIFT karakters), 'End-to-end-ID' (alphanumeriek, vrij in te vullen door de tegenpartij), 'Omschrijving' (wederom SWIFT karakters).
Als ze de volgorde van de velden hadden omgegooid, was het geen probleem (bijvoorbeeld de BIC na de naam), maar nu zit je met een 'naam' veld (die spaties mag bevatten, maar bijvoorbeeld ook een getallenreeks kan bevatten), dan een spatie, dan een aflphanumeriek 'ete-id', dan een spatie en dan een omschrijving.
Vooralsnog lees ik de ASCII bestanden maar weer uit, die waren veel makkelijker qua SEPA toevoegingen (in omschrijving: "Iban: <iban> Bic: <bic>" etc.)
Enige nadeel is dat je de saldo's en totalen mist, die je bij MT940 wel meekrijgt.
Blijkbaar hebben ze intern de velden wel goed gescheiden (zie ASCII), maar is er gewoon niet goed nagedacht over hoe ze het in MT940 implementeren.
Zoals ik al eerder noemde zijn spaties niet echt handige scheidingstekens voor deze velden en is de volgorde ook nog eens zo gekozen dat het extra tegenwerkt...

Een (fictief, maar op realiteit gebaseerd) voorbeeld wat (bij mij) altijd mis gaat:
:86:0123456789 NLxxINGB0123456789 INGBNL2A www.bestelling.nl 01-01-2
013 13:37 0010000123456789 1337 0010000123456789 Order 1337 bestelling.nl

[ Voor 8% gewijzigd door MichielioZ op 03-12-2013 20:50 . Reden: Voorbeeld toegevoegd ]

Iedereen wil terug naar de natuur, maar niemand wil lopend...


  • IceM
  • Registratie: Juni 2003
  • Laatst online: 07:42
Heb je al contact opgenomen met de ING over dit probleem? Dit is vrijwel niet op te lossen voor alle mogelijke combinaties.

Misschien kun je de oude ASCII files combineren met de nieuwe sepa files om zo de correcte velden te bepalen?

...


  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Klopt, in mijn :86: voorbeelden die van ING komen is het al een bende.
Per 1 februari 2014 moet je toch over op de ISO 20022 XML notatie.
De ING heeft hier ook informatie over, inclusief validatie tools.

Maak je niet druk, dat doet de compressor maar

Pagina: 1