Regular Expressions adres formaten
Ik heb een grote lijst met adressen en telefoonnummers. Die lijst wil ik netjes verwerken en in een mysql database stoppen. Het lastige is dat er een aantal verschillende formaten zijn waarin de adressen worden weergeven. Ik dacht dat ik er met regular expressions uit zou komen, maar mijn kennis daarvan is niet groot genoeg. Graag krijg ik hier wat hulp bij.
Dit zijn de straatformaten:
Rodekruislaan 23
2e Rodekruislaan 23
2e Rode Kruislaan 23
Rodekruislaan 23 B
2e Rodekruislaan 23 B
2e Rode Kruis Laan 23 B
Rodekruislaan 23/C
2e Rodekruislaan 23/C
Rodekruislaan 23C 001
2e Rodekruislaan 23C 001
Rodekruislaan 23 C 001
Rodekruislaan 23 C 001B
etc
Ik wil graag de straat, het nummer en de toevoeging opsplitsen. Tot nu toe heb ik dit:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
if (preg_match('/(?P<straat>.*)\s(?P<nummer>\d*)\s(?P<toevoeging>\w*)$/', $string, $matches)) {
var_dump($matches);
}
?>
if (preg_match('/(?P<straat>.*)\s(?P<nummer>\d*)\s(?P<toevoeging>\w*)$/', $string, $matches)) {
var_dump($matches);
}
?>
Ik krijg dan de volgende array terug:
array (size=8)
0 => string 'Rode Kruislaan 1302' (length=19)
'straat' => string 'Rode Kruislaan' (length=14)
1 => string 'Rode Kruislaan' (length=14)
'nummer' => string '130' (length=3)
2 => string '130' (length=3)
3 => string '2' (length=1)
'toevoeging' => string '' (length=0)
4 => string '' (length=0)
Ik snap niet waarom het nummer afgebroken wordt. Kan iemand mij dat vertellen? En weet jij of er een formaat is waarmee ik alle typen adressen kan formateren? Het kan dus zijn dat een straatnaam meerdere spaties heeft, wat het ook lastig maakt, denk ik. Ook kan het zijn dat de string begint met een nummer, zoals je ziet in de voorbeelden hier bovven.
Alvast super bedankt, ik weet dat dit een lastige vraag is.
Groetjes,
Arthur
Gewijzigd op 06/09/2016 18:58:39 door Arthur Nolles
Grappig, hoe ga je adressen als Laan 1940-1945 12 dan goed oppakken? Dit soort dingen leidt *altijd* tot gezeur, laat mensen gewoon zelf hun adres invullen zoals het hoort. Dus met gewoon velden voor straat, huisnummer etc. Mensen weten veel beter waar ze wonen dan wat jij denkt ervan te kunnen maken.
Het gaat om een lijst die ik al heb, dus niet om data die ik nog moet verzamelen.
Toevoeging op 06/09/2016 20:10:24:
Daarnaast weet ik dat er altijd uitzonderingen zullen zijn. In het geval van Laan 1945 zal ik gewoon handmatig een aanpassing moeten doen en dat vind ik niet zo erg. Maar ik wil graag dat het bulk van de straatnamen goed geformateerd worden en daarbij kan ik hulp gebruiken. Ik stel hulp dan ook zeer op prijs.
Code (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
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
<?php
echo '<h3>Array</h3>';
$haystack = array("Rodekruislaan 23",
"2e Rodekruislaan 23",
"2e Rode Kruislaan 23",
"Rodekruislaan 23 B",
"2e Rodekruislaan 23 B",
"2e Rode Kruis Laan 23 B",
"Rodekruislaan 23/C",
"2e Rodekruislaan 23/C",
"Rodekruislaan 23C 001",
"2e Rodekruislaan 23C 001",
"Rodekruislaan 23 C 001",
"Rodekruislaan 23 C 001B");
echo '<pre>';
print_r($haystack);
echo '</pre>';
echo '<h3>Output Array na preg_match</h3>';
$output = array();
for($x = 0; $x < count($haystack); $x++) {
preg_match("/^(.+)\s(\d+)\s?(.?)(.*)?/", $haystack[$x], $output_array);
if(count($output_array) > 0) {
$output[] = $output_array;
}
}
echo '<pre>';
print_r($output);
echo '</pre>';
echo '<h3>Netjes geprint</h3>';
for($i = 0; $i < count($output); $i++) {
for($x = 0; $x < count($output[$i]); $x++) {
echo ' {' . $output[$i][$x] . '} ';
}
echo "<br>";
}
?>
echo '<h3>Array</h3>';
$haystack = array("Rodekruislaan 23",
"2e Rodekruislaan 23",
"2e Rode Kruislaan 23",
"Rodekruislaan 23 B",
"2e Rodekruislaan 23 B",
"2e Rode Kruis Laan 23 B",
"Rodekruislaan 23/C",
"2e Rodekruislaan 23/C",
"Rodekruislaan 23C 001",
"2e Rodekruislaan 23C 001",
"Rodekruislaan 23 C 001",
"Rodekruislaan 23 C 001B");
echo '<pre>';
print_r($haystack);
echo '</pre>';
echo '<h3>Output Array na preg_match</h3>';
$output = array();
for($x = 0; $x < count($haystack); $x++) {
preg_match("/^(.+)\s(\d+)\s?(.?)(.*)?/", $haystack[$x], $output_array);
if(count($output_array) > 0) {
$output[] = $output_array;
}
}
echo '<pre>';
print_r($output);
echo '</pre>';
echo '<h3>Netjes geprint</h3>';
for($i = 0; $i < count($output); $i++) {
for($x = 0; $x < count($output[$i]); $x++) {
echo ' {' . $output[$i][$x] . '} ';
}
echo "<br>";
}
?>
Toevoeging op 06/09/2016 23:11:42:
"Netjes geprint" wordt het zo weergegeven:
{Rodekruislaan 23} {Rodekruislaan} {23} {} {}
{2e Rodekruislaan 23} {2e Rodekruislaan} {23} {} {}
{2e Rode Kruislaan 23} {2e Rode Kruislaan} {23} {} {}
{Rodekruislaan 23 B} {Rodekruislaan} {23} {B} {}
{2e Rodekruislaan 23 B} {2e Rodekruislaan} {23} {B} {}
{2e Rode Kruis Laan 23 B} {2e Rode Kruis Laan} {23} {B} {}
{Rodekruislaan 23/C} {Rodekruislaan} {23} {/} {C}
{2e Rodekruislaan 23/C} {2e Rodekruislaan} {23} {/} {C}
{Rodekruislaan 23C 001} {Rodekruislaan 23C} {001} {} {}
{2e Rodekruislaan 23C 001} {2e Rodekruislaan 23C} {001} {} {}
{Rodekruislaan 23 C 001} {Rodekruislaan 23 C} {001} {} {}
{Rodekruislaan 23 C 001B} {Rodekruislaan 23 C} {001} {B} {}
Toevoeging op 06/09/2016 23:13:56:
Nog een vraag; ik snap niet goed waarvoor de vraagtekens gebruikt worden, bijvoorbeeld: \s?. Kun je me dat vertellen, want in de documentatie kom ik er niet echt uit.
Dan wordt het netjes gesplits.
EDIT : te vroeg gegokt, dan maar met de hand wijzigen.
\s? kijkt of er een spatie is.
Gewijzigd op 06/09/2016 23:41:52 door Adoptive Solution
Toevoeging op 06/09/2016 23:50:04:
Ik volg je niet helemaal, wat bedoel je met 'te vroeg gegokt'? Ik kan de records niet echt met de hand wijzigen, ik heb 2 miljoen records die geformateerd moeten worden.
Gewijzigd op 06/09/2016 23:44:06 door Arthur Nolles
Toevoeging op 07/09/2016 00:18:40:
Verwijder met zoek/vervang de spaties en / uit de huisnummers en gebruik dan dit :
Het resultaat is dan beter.
Je moet dan alleen nog bv. 001B met de hand splitsen.
Gewijzigd op 07/09/2016 00:19:44 door Adoptive Solution
En dan ga ik er nog vanuit dat er ook werkelijk een huisnummer in je adres staat.
Alles wat je overhoudt:
plein 1940 12
Willem 3 laan 13
1e kerkstraat 3
kerkstraat 42F1
laat je door een stagiair oplossen.
https://gist.github.com/devotis/c574beaf73adcfd74997
Maar ik denk dat ik zelf een andere 'oplossingsstrategie' zou volgen. Voor Nederlandse adressen gelden enkele beperkingen: het huisnummer en de huisnummertoevoeging mogen beide niet langer zijn dan 5 karakters. Inclusief scheidingsteken tussen huisnummer en huisnummertoevoeging kom je daarmee op maximaal 11 karakters vanaf het einde van de adresregel. Die regels zijn het uitgangspunt van de volgende functie:
Code (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
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
<?php
/**
* @param string $address
* @return array
*/
function getAddressArray($address)
{
$address = trim($address);
$street = $address;
$home_number_extension = '';
$home_number = substr($address, -11);
$max = strlen($home_number);
for ($i=0; $i < $max; $i++) {
if (is_numeric($home_number{$i})) {
$home_number = substr($address, -$max + $i);
$street = substr($address, 0, strlen($address) - $max + $i);
break;
}
}
if ($i == $max) {
$home_number = '';
$home_number_extension = '';
}
for ($i = 0; $i < strlen($home_number); $i++) {
if (!is_numeric($home_number{$i})) {
$home_number_extension = substr($home_number, $i);
$home_number = substr($home_number, 0, $i);
break;
}
}
return array(trim($street), trim($home_number), trim($home_number_extension));
}
// Test cases
$cases = array(
'Rodekruislaan 23',
'2e Rodekruislaan 23',
'2e Rode Kruislaan 23',
'Rodekruislaan 23 B',
'2e Rodekruislaan 23 B',
'2e Rode Kruis Laan 23 B',
'Rodekruislaan 23/C',
'2e Rodekruislaan 23/C',
'Rodekruislaan 23C 001',
'2e Rodekruislaan 23C 001',
'Rodekruislaan 23 C 001',
'Rodekruislaan 23 C 001B',
);
// Test
echo '<pre>';
foreach ($cases as $case) {
var_dump($case);
var_dump(getAddressArray($case));
}
?>
/**
* @param string $address
* @return array
*/
function getAddressArray($address)
{
$address = trim($address);
$street = $address;
$home_number_extension = '';
$home_number = substr($address, -11);
$max = strlen($home_number);
for ($i=0; $i < $max; $i++) {
if (is_numeric($home_number{$i})) {
$home_number = substr($address, -$max + $i);
$street = substr($address, 0, strlen($address) - $max + $i);
break;
}
}
if ($i == $max) {
$home_number = '';
$home_number_extension = '';
}
for ($i = 0; $i < strlen($home_number); $i++) {
if (!is_numeric($home_number{$i})) {
$home_number_extension = substr($home_number, $i);
$home_number = substr($home_number, 0, $i);
break;
}
}
return array(trim($street), trim($home_number), trim($home_number_extension));
}
// Test cases
$cases = array(
'Rodekruislaan 23',
'2e Rodekruislaan 23',
'2e Rode Kruislaan 23',
'Rodekruislaan 23 B',
'2e Rodekruislaan 23 B',
'2e Rode Kruis Laan 23 B',
'Rodekruislaan 23/C',
'2e Rodekruislaan 23/C',
'Rodekruislaan 23C 001',
'2e Rodekruislaan 23C 001',
'Rodekruislaan 23 C 001',
'Rodekruislaan 23 C 001B',
);
// Test
echo '<pre>';
foreach ($cases as $case) {
var_dump($case);
var_dump(getAddressArray($case));
}
?>
Woon je daar op nummer 12, dan verhuist bovenstaand script je naar huisnummer 1933 met toevoeging 12.
Misschien zou het nog een optie zijn om op basis van de postcode via een API een straatnaam erbij te zoeken voor de twijfelgevallen.
Met een beetje geluk matcht de gevonden straatnaam ook met de schrijfwijze van het adres in je lijst.
Maar met "BURG. WUITEWEG" vs "Burgemeester Wuiteweg" heb je evengoed nog een uitdaging.
Straatnamen vergelijken via een postcode-API is inderdaad ook slim. Eventueel kun je dat nog combineren met een soort spellingcorrectie die alle 'Burg. ' vervangt door 'Burgemeester '.
Ik wil iedereen heel hartelijk bedanken, vooral Ward van der Put. Jouw oplossing lijkt in alle gevallen de juiste data te weergeven. Heel veel dank.
De enige manier om dit probleem (naar de toekomst toe) op te lossen / te voorkomen is zoals @Ben aangeeft: het introduceren van aparte invoervelden.
Ik snap dat je je invoer die je nu reeds hebt wil fixen maar ik hoop dat dit ook duidelijk maakt dat deze ook soms echt niet klopt. Je moet niet proberen recht te breien wat krom is.
Idealiter heb je dus een mechanisme die al bij invoer kijkt of de informatie klopt. Bijvoorbeeld een autocomplete op grond van huisnummer + postcode. En voor de randgevallen kun je je adres handmatig in- of aanvullen.
Dit alles zodat de informatie die de database ingaat klopt en gestructureerd staat opgeslagen zodat je niet achteraf hier doorheen moet baggeren met allerlei vage regexes om de boel weer te fixen :/.
Het is altijd lekker makkelijk om e.e.a. aan te nemen. Maar zoals ik eerder zei heb ik deze data zo aangeleverd gekregen en heb ik het hier mee te doen - ik was niet degene die de data heeft verzameld. Is inderdaad vervelend, maar geen preek waard. Ik denk dat wat je zegt voor iedereen wel duidelijk was.
En als dat ook niet mogelijk is dat loont het wellicht de moeite om eens een balletje op te gooien bij deze partij zodat ze hun eigen informatiehuishouding op orde stellen.
Misschien zit men niet te wachten op dit soort (bijdehante?) opmerkingen. Aan de andere kant, als ik door de luiheid / stupiditeit van anderen meer werk heb, dan zou ik daar iets van zeggen.
Je hoeft niet zomaar alles te accepteren wat over de schutting gegooid wordt.
Soms moet je gewoon keuzes maken!
Verder is dit ook niet echt de vraag van de topicstarter, en heeft die ook aangegeven niet anders te kunnen. Dus we kunnen ons maar beter bij deze 'wereldverbetering' neerleggen.
De enige juiste oplossing is dan ook het repareren van (het aanleveren van) de input. Alle andere oplossingen, hoe goed deze ook werken, zijn symptoombestrijdingen van (lees: ad hoc oplossingen voor) het oorspronkelijke probleem.
Dit is geen wereldverbetering, dit is mensen confronteren met gemaakte keuzen. En proberen te achterhalen of deze beslissingen ergens op gebaseerd zijn. Of dat er uberhaupt is nagedacht over hoe je informatie wilt gaan gebruiken / inzetten.
Niets is zo verkwistend als voortborduren op een slecht ontwerp. Dit is dan ook niet iets wat aangemoedigd zou moeten worden.
EDIT: kan het ergens wel plaatsen dat TS enigszins geagiteerd reageert, niemand vind het immers leuk om andermans rommel op te ruimen. Zeg daar dan ook wat van.
Gewijzigd op 09/09/2016 15:05:07 door Thomas van den Heuvel
Een discussie over het 'hoe wel/niet aanleveren van adressen en in welk formaat' vind ik niet veel waard in dit topic. Daar mag wat mij betreft een nieuw topic voor worden aangemaakt. De topicstarter heeft immers al aangegeven zijn lijst al zo te hebben, en daar weinig aan te kunnen veranderen.
Gewijzigd op 09/09/2016 15:12:50 door - Ariën -
Edit:
**knip**
Ja, nu weten we je standpunt wel! Maar dat had ook vriedelijker gemogen!
Ja, nu weten we je standpunt wel! Maar dat had ook vriedelijker gemogen!
Gewijzigd op 09/09/2016 23:24:57 door - Ariën -