Code snippets formatteren Nederlandse kenteken

UPDATE 16 januari 2014: Deze posting heeft een update gekregen wegens introductie sidecode11 tot en met 14. Alle codevoorbeelden (ook degene in de comments) zijn aangepast aan deze nieuwe sidecodes.

In mijn dagelijkse werk heb ik veel te maken met voertuiginformatie en ontsluiten van deze info op basis van een kenteken. Deze ontsluitingen worden door klanten van VWE in allerlei systemen gedaan.

Het valt daarbij op dat bij implementaties voor verschillende manieren wordt gekozen om een kenteken uit te vragen. Het draait daarbij met name om het gebruik van de streepjes van een kenteken. Hier wordt soms heel veel belang aan gehecht, terwijl de streepjes eigenlijk alleen maar een nut hebben voor de leesbaarheid/herkenbaarheid van een Nederlands kenteken.

In deze posting zal ik hier eens aandacht aan besteden.

Streep of niet?

In het ene voertuiginformatiesysteem wordt een simpel tekstveld gebruikt, waarbij je per se de streepjes moet noteren (oftewel 8 karakters lang max).

In het andere systeem wordt het uitvragen van een kenteken uitgesplitst in 3 gedeeltes, zodat je de streepjes niet hoeft in te vullen. Sinds het gebruik van de nieuwe sidecode krijg je op dit soort de onhebbelijkheid dat je nooit weet of je in het middenstuk 2 of 3 karakters kwijt kan. Persoonlijk vind ik dit de slechtste implementatie die er is. Het leidt tot onduidelijkheid bij de invuller, waardoor de kans op fouten groter worden.

Een implementatie die ik voorsta, en die bij VWE wordt toegepast, is een tekstveld waarbij je een kenteken met of zonder streepjes mag invullen. Op basis van input wordt het ingevulde kenteken in de juiste sidecode geformatteerd als dat nodig is (eindgebruikers vinden een geformatteerd kenteken vaak herkenbaarder). Bij het valideren van de input worden alle streepjes verwijderd, zodat het kenteken “geschoond” aangeleverd kan worden aan bijvoorbeeld onze webservices. Je kan nog overwegen om alles in uppercase of lowercase te zetten, maar dat maakt eigenlijk niet uit. Kentekens an sich zijn niet case-sensitive.

Daarnaast kan je een functie inbouwen om het geschoonde kenteken weer om te zetten in juist geformatteerd kenteken. Hierbij zijn de hoofdletters en juiste positionering van de streepjes wel essentieel. Hierdoor is het voor een eindgebruiker mogelijk om een kenteken als 83-RS-PH in te vullen op de volgende manieren:

– 83rsph

– 83RSPH

– 83-rs-ph

– 83-RS-PH

– 8-3RS-PH

– 83-RSP-H

etc.

Het geschoond kenteken is in dit gevallen altijd 83rsph. Het geformatteerde kenteken zou er dan altijd als 83-RS-PH moeten uitzien.

Code snippet kenteken formatteren

Hoe doe je dat formatteren? Ik heb ooit van 1 van onze programmeurs het volgende stukje code ontvangen die ik mocht delen met onze klanten. Dit stukje code is geschreven in .net (dacht ik) en mag “as-is” gebruikt worden. Het maakt gebruik van regex om het ingevoerde kenteken te valideren:

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
Public Class VehicleFunctions
 
Public Shared Function GetSidecodeLicenseplate(ByVal Licenseplate As String) As String
 
Dim arrSC(13) As String
Dim scUitz As String = String.Empty
 
Licenseplate = Licenseplate.Replace("-", "").ToUpper
 
arrSC(0) = "^[a-zA-Z]{2}[d]{2}[d]{2}$" ' 1 XX-99-99
arrSC(1) = "^[d]{2}[d]{2}[a-zA-Z]{2}$" ' 2 99-99-XX
arrSC(2) = "^[d]{2}[a-zA-Z]{2}[d]{2}$" ' 3 99-XX-99
arrSC(3) = "^[a-zA-Z]{2}[d]{2}[a-zA-Z]{2}$" ' 4 XX-99-XX
arrSC(4) = "^[a-zA-Z]{2}[a-zA-Z]{2}[d]{2}$" ' 5 XX-XX-99
arrSC(5) = "^[d]{2}[a-zA-Z]{2}[a-zA-Z]{2}$" ' 6 99-XX-XX
arrSC(6) = "^[d]{2}[a-zA-Z]{3}[d]{1}$" ' 7 99-XXX-9
arrSC(7) = "^[d]{1}[a-zA-Z]{3}[d]{2}$" ' 8 9-XXX-99
arrSC(8) = "^[a-zA-Z]{2}[d]{3}[a-zA-Z]{1}$" ' 9 XX-999-X
arrSC(9) = "^[a-zA-Z]{1}[d]{3}[a-zA-Z]{2}$" ' 10 X-999-XX
arrSC(10) = "^[a-zA-Z]{3}[d]{2}[a-zA-Z]{1}$" ' 11 XXX-99-X
arrSC(11) = "^[a-zA-Z]{1}[d]{2}[a-zA-Z]{3}$" ' 12 X-99-XXX
arrSC(12) = "^[d]{1}[a-zA-Z]{2}[d]{3}$" ' 13 9-XX-999
arrSC(13) = "^[d]{3}[a-zA-Z]{2}[d]{1}$" ' 14 999-XX-9
 
'except licenseplates for diplomats
scUitz = "^CD[ABFJNST][0-9]{1,3}$" 'for example: CDB1 of CDJ45
 
For i As Integer = 0 To 13
If System.Text.RegularExpressions.Regex.IsMatch(Licenseplate, arrSC(i)) Then
Return (i + 1).ToString
End If
Next
 
If System.Text.RegularExpressions.Regex.IsMatch(Licenseplate, scUitz) Then
Return "CD"
End If
 
Return String.Empty
 
End Function
 
Public Shared Function FormatLicenseplate(ByVal Licenseplate As String, ByVal Sidecode As String) As String
 
Licenseplate = Licenseplate.Replace("-", "").ToUpper
 
Select Case Sidecode
 
Case "1", "2", "3", "4", "5", "6"
Return Licenseplate.Substring(0, 2) & "-" & Licenseplate.Substring(2, 2) & "-" & Licenseplate.Substring(4, 2)
 
Case "7", "9"
Return Licenseplate.Substring(0, 2) & "-" & Licenseplate.Substring(2, 3) & "-" & Licenseplate.Substring(5, 1)
 
Case "8", "10"
Return Licenseplate.Substring(0, 1) & "-" & Licenseplate.Substring(1, 3) & "-" & Licenseplate.Substring(4, 2)
 
Case "11", "14"
Return Licenseplate.Substring(0, 3) & "-" & Licenseplate.Substring(3, 2) & "-" & Licenseplate.Substring(5, 1)
 
Case "12", "13"
Return Licenseplate.Substring(0, 1) & "-" & Licenseplate.Substring(1, 2) & "-" & Licenseplate.Substring(3, 3)
 
Case Else
'No formatting with sidecode 'CD'
Return Licenseplate
 
End Select
 
End Function
 
End Class

Een klant van VWE heeft deze code ooit in Delphi nagemaakt en gedeeld met VWE:

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
function bepaalKentekenIndeling(sKenteken: String): Integer;
const
arrSC: array[0..14] of string =
(
'^[a-zA-Z]{2}[d]{2}[d]{2}$', // 0 XX-99-99
'^[d]{2}[d]{2}[a-zA-Z]{2}$', // 1 99-99-XX
'^[d]{2}[a-zA-Z]{2}[d]{2}$', // 2 99-XX-99
'^[a-zA-Z]{2}[d]{2}[a-zA-Z]{2}$', // 3 XX-99-XX
'^[a-zA-Z]{2}[a-zA-Z]{2}[d]{2}$', // 4 XX-XX-99
'^[d]{2}[a-zA-Z]{2}[a-zA-Z]{2}$', // 5 99-XX-XX
'^[d]{2}[a-zA-Z]{3}[d]{1}$', // 6 99-XXX-9
'^[d]{1}[a-zA-Z]{3}[d]{2}$', // 7 9-XXX-99
'^[a-zA-Z]{2}[d]{3}[a-zA-Z]{1}$', // 8 XX-999-X
'^[a-zA-Z]{1}[d]{3}[a-zA-Z]{2}$', // 9 X-999-XX
'^[a-zA-Z]{3}[d]{2}[a-zA-Z]{1}$', // 10 XXX-99-X
'^[a-zA-Z]{1}[d]{2}[a-zA-Z]{3}$', // 11 X-99-XXX
'^[d]{1}[a-zA-Z]{2}[d]{3}$', // 12 9-XX-999
'^[d]{3}[a-zA-Z]{2}[d]{1}$', // 13 999-XX-9
'^CD[ABFJNST][0-9]{1,3}$' // 14 except licenseplates for diplomats for example: CDB1 of CDJ45
);
var
iT1: Integer;
PerlRegEx: TPerlRegEx;
begin
PerlRegEx := TPerlRegEx.Create(nil);
try
sKenteken := UpperCase(StringReplace(sKenteken, '-', '', [rfReplaceAll]));
//
PerlRegEx.Subject := sKenteken;
for iT1 := 0 to 14 do
begin
PerlRegEx.RegEx := arrSC[iT1];
if PerlRegEx.Match then
begin
Result := iT1;
Exit;
end;
end;
Result := -1;
finally
PerlRegEx.Free;
end;
end;
 
function formateerKenteken(sKentekenIn: String; iIndelingId: Integer): String;
var
sKenteken: String;
begin
sKenteken := UpperCase(StringReplace(sKentekenIn, '-', '', [rfReplaceAll]));
case iIndelingId of
0, 1, 2, 3, 4, 5:
Result := Copy(sKenteken, 1, 2) + '-' + Copy(sKenteken, 3, 2) + '-' + Copy(sKenteken, 5, 2);
6, 8:
Result := Copy(sKenteken, 1, 2) + '-' + Copy(sKenteken, 3, 3) + '-' + Copy(sKenteken, 6, 1);
7, 9:
Result := Copy(sKenteken, 1, 1) + '-' + Copy(sKenteken, 2, 3) + '-' + Copy(sKenteken, 5, 2);
10, 13:
Result := Copy(sKenteken, 1, 3) + '-' + Copy(sKenteken, 4, 2) + '-' + Copy(sKenteken, 6, 1);
11, 12:
Result := Copy(sKenteken, 1, 1) + '-' + Copy(sKenteken, 2, 2) + '-' + Copy(sKenteken, 4, 3);
else // No formatting with sKentekenIndeling '14'
Result := sKentekenIn;
end;
end;

34 gedachten over “Code snippets formatteren Nederlandse kenteken”

  1. Geniaal! Ik heb de javascript variant ervoor gemaakt:

    function GetSidecodeLicenseplate(Licenseplate){
     
    	var arrSC = new Array;
    	var scUitz = '';
     
    	Licenseplate = Licenseplate.replace('-', '').toUpperCase();
     
    	arrSC[0] = /^[a-zA-Z]{2}[d]{2}[d]{2}$/         //   1       XX-99-99
    	arrSC[1] = /^[d]{2}[d]{2}[a-zA-Z]{2}$/         //   2       99-99-XX
    	arrSC[2] = /^[d]{2}[a-zA-Z]{2}[d]{2}$/         //   3       99-XX-99
    	arrSC[3] = /^[a-zA-Z]{2}[d]{2}[a-zA-Z]{2}$/     //   4       XX-99-XX
    	arrSC[4] = /^[a-zA-Z]{2}[a-zA-Z]{2}[d]{2}$/     //   5       XX-XX-99
    	arrSC[5] = /^[d]{2}[a-zA-Z]{2}[a-zA-Z]{2}$/     //   6       99-XX-XX
    	arrSC[6] = /^[d]{2}[a-zA-Z]{3}[d]{1}$/         //   7       99-XXX-9
    	arrSC[7] = /^[d]{1}[a-zA-Z]{3}[d]{2}$/         //   8       9-XXX-99
    	arrSC[8] = /^[a-zA-Z]{2}[d]{3}[a-zA-Z]{1}$/     //   9       XX-999-X
    	arrSC[9] = /^[a-zA-Z]{1}[d]{3}[a-zA-Z]{2}$/     //   10      X-999-XX
    	arrSC[10] = /^[a-zA-Z]{3}[d]{2}[a-zA-Z]{1}$/     //   11      XXX-99-X
    	arrSC[11] = /^[a-zA-Z]{1}[d]{2}[a-zA-Z]{3}$/     //   12      X-99-XXX
    	arrSC[12] = /^[d]{1}[a-zA-Z]{2}[d]{3}$/     	  //   13      9-XX-999
    	arrSC[13] = /^[d]{3}[a-zA-Z]{2}[d]{1}$/         //   14      999-XX-9	
     
    	//except licenseplates for diplomats
    	scUitz = '^CD[ABFJNST][0-9]{1,3}$'              //for example: CDB1 of CDJ45
     
    	for(i=0;i<arrSC.length;i++){
    		if (Licenseplate.match(arrSC[i])) {
    			return i+1;
    		}
    	}
    	if (Licenseplate.match(scUitz)) {
    		return 'CD';
    	}
    	return false;
    }
     
    function FormatLicenseplate(Licenseplate,Sidecode) {
     
    	Licenseplate = Licenseplate.replace('-', '').toUpperCase();
     
    	if (Sidecode <= 6) {
    			return Licenseplate.substr(0, 2) + '-' + Licenseplate.substr(2, 2) + '-' + Licenseplate.substr(4, 2)
    	}
    	if (Sidecode == 7 || Sidecode == 9) {
    			return Licenseplate.substr(0, 2) + '-' + Licenseplate.substr(2, 3) + '-' + Licenseplate.substr(5, 1)
    	}
    	if (Sidecode == 8 || Sidecode == 10) {
    			return Licenseplate.substr(0, 1) + '-' + Licenseplate.substr(1, 3) + '-' + Licenseplate.substr(4, 2)
    	}
    	if (Sidecode == 11 || Sidecode == 14) {
    			return Licenseplate.substr(0, 3) + '-' + Licenseplate.substr(3, 2) + '-' + Licenseplate.substr(5, 1)
    	}
    	if (Sidecode == 12 || Sidecode == 13) {
    			return Licenseplate.substr(0, 1) + '-' + Licenseplate.substr(1, 2) + '-' + Licenseplate.substr(3, 3)
    	}
    	return Licenseplate
    }
    1. Regel 15 moet veranderd worden naar:

      Licenseplate = Licenseplate.replace(/-/g, ”).toUpperCase();

      Anders wordt alleen het eerste streepje weggehaald.

  2. En voor de liefhebbers in PHP:

    function GetSidecodeLicenseplate($Licenseplate){
    		$arrSC = array();
    		$scUitz = '';
    		$Licenseplate = strtoupper(str_replace('-', '',$Licenseplate));
    		$arrSC[0] = '/^[a-zA-Z]{2}[d]{2}[d]{2}$/';         //   1       XX-99-99
    		$arrSC[1] = '/^[d]{2}[d]{2}[a-zA-Z]{2}$/';         //   2       99-99-XX
    		$arrSC[2] = '/^[d]{2}[a-zA-Z]{2}[d]{2}$/';         //   3       99-XX-99
    		$arrSC[3] = '/^[a-zA-Z]{2}[d]{2}[a-zA-Z]{2}$/';     //   4       XX-99-XX
    		$arrSC[4] = '/^[a-zA-Z]{2}[a-zA-Z]{2}[d]{2}$/';     //   5       XX-XX-99
    		$arrSC[5] = '/^[d]{2}[a-zA-Z]{2}[a-zA-Z]{2}$/';     //   6       99-XX-XX
    		$arrSC[6] = '/^[d]{2}[a-zA-Z]{3}[d]{1}$/';         //   7       99-XXX-9
    		$arrSC[7] = '/^[d]{1}[a-zA-Z]{3}[d]{2}$/';         //   8       9-XXX-99
    		$arrSC[8] = '/^[a-zA-Z]{2}[d]{3}[a-zA-Z]{1}$/';     //   9       XX-999-X
    		$arrSC[9] = '/^[a-zA-Z]{1}[d]{3}[a-zA-Z]{2}$/';     //   10      X-999-XX
    		$arrSC[10] = '/^[a-zA-Z]{3}[d]{2}[a-zA-Z]{1}$/';     //   11      XXX-99-X
    		$arrSC[11] = '/^[a-zA-Z]{1}[d]{2}[a-zA-Z]{3}$/';     //   12      X-99-XXX
    		$arrSC[12] = '/^[d]{1}[a-zA-Z]{2}[d]{3}$/';     	  //   13      9-XX-999
    		$arrSC[13] = '/^[d]{3}[a-zA-Z]{2}[d]{1}$/';         //   14      999-XX-9				
     
    		//except licenseplates for diplomats
    		$scUitz = '/^CD[ABFJNST][0-9]{1,3}$/';              //for example: CDB1 of CDJ45
    		for($i=0;$i<count($arrSC);$i++){
    			if (preg_match($arrSC[$i],$Licenseplate)) {
    				return $i+1;
    			}
    		}
    		if (preg_match($scUitz,$Licenseplate)) {
    			return 'CD';
    		}
    		return false;
    	}
     
    	function FormatLicenseplate($Licenseplate,$Sidecode) {
    		$Licenseplate = strtoupper(str_replace('-', '',$Licenseplate));
    		if ($Sidecode <= 6 && $Sidecode > 0) {
    			return substr($Licenseplate,0,2) . '-' . substr($Licenseplate,2,2) . '-' . substr($Licenseplate,4,2);
    		}
    		if ($Sidecode == 7 || $Sidecode == 9) {
    			return substr($Licenseplate,0,2) . '-' . substr($Licenseplate,2,3) . '-' . substr($Licenseplate,5,1);
    		}
    		if ($Sidecode == 8 || $Sidecode == 10) {
    			return substr($Licenseplate,0,1) . '-' . substr($Licenseplate,1,3) . '-' . substr($Licenseplate,4,2);
    		}
    		if ($Sidecode == 11 || $Sidecode == 14) {
    			return substr($Licenseplate,0,3) . '-' . substr($Licenseplate,3,2) . '-' . substr($Licenseplate,5,1);
    		}
    		if ($Sidecode == 12 || $Sidecode == 13) {
    			return substr($Licenseplate,0,1) . '-' . substr($Licenseplate,1,2) . '-' . substr($Licenseplate,3,3);
    		}		
     
    		return $Licenseplate;
    	}
    1. Als je gewoon wil prettifien:

      function prettyPlate($plate) {
      $sideCode[1] = array('/([^0-9]{2})(\d{2})(\d{2})/', '/$1-$2-$3/'); # XX-99-99
      $sideCode[2] = array('/(\d{2})(\d{2})([^0-9]{2})/', '/$1-$2-$3/'); # 99-99-XX
      $sideCode[3] = array('/(\d{2})([^0-9]{2})(\d{2})/', '/$1-$2-$3/'); # 99-XX-99
      $sideCode[4] = array('/([^0-9]{2})(\d{2})([^0-9]{2})/', '/$1-$2-$3/'); # XX-99-XX
      $sideCode[5] = array('/([^0-9]{2})([^0-9]{2})(\d{2})/', '/$1-$2-$3/'); # XX-XX-99
      $sideCode[6] = array('/(\d{2})([^0-9]{2})([^0-9]{2})/', '/$1-$2-$3/'); # 99-XX-XX
      $sideCode[7] = array('/(\d{2})([^0-9]{3})(\d{1})/', '/$1-$2-$3/'); # 99-XXX-9
      $sideCode[8] = array('/(\d{1})([^0-9]{3})(\d{2})/', '/$1-$2-$3/'); # 9-XXX-99
      $sideCode[9] = array('/([^0-9]{2})(\d{3})([^0-9]{1})/', '/$1-$2-$3/'); # XX-999-X
      $sideCode[10] = array('/([^0-9]{1})(\d{3})([^0-9]{2})/', '/$1-$2-$3/'); # X-999-XX
      $sideCode[11] = array('/([^0-9]{3})(\d{2})([^0-9]{1})/', '/$1-$2-$3/'); # XXX-99-X
      $sideCode[12] = array('/([^0-9]{1})(\d{2})([^0-9]{3})/', '/$1-$2-$3/'); # X-99-XXX
      $sideCode[13] = array('/(\d{1})([^0-9]{2})(\d{3})/', '/$1-$2-$3/'); # 9-XX-999
      $sideCode[14] = array('/(\d{3})([^0-9]{2})(\d{1})/', '/$1-$2-$3/'); # 999-XX-9

      for($i=1;$i ".prettyPlate("XX9999")."";
      echo "9999XX => ".prettyPlate("9999XX")."";
      echo "99XX99 => ".prettyPlate("99XX99")."";
      echo "XX99XX => ".prettyPlate("XX99XX")."";
      echo "XXXX99 => ".prettyPlate("XXXX99")."";
      echo "99XXXX => ".prettyPlate("99XXXX")."";
      echo "99XXX9 => ".prettyPlate("99XXX9")."";
      echo "9XXX99 => ".prettyPlate("9XXX99")."";
      echo "XX999X => ".prettyPlate("XX999X")."";
      echo "X999XX => ".prettyPlate("X999XX")."";
      echo "XXX99X => ".prettyPlate("XXX99X")."";
      echo "X99XXX => ".prettyPlate("X99XXX")."";
      echo "9XX999 => ".prettyPlate("9XX999")."";
      echo "999XX9 => ".prettyPlate("999XX9")."";

  3. En bij deze dan ook de Java code:

    static public int getSidecodeLicenseplate(String licenseplate){
    		licenseplate = licenseplate.replace("-", "").toUpperCase();
     
    		Pattern[] arrSC = new Pattern[10];
    		Pattern scUitz;
     
    		arrSC[0] = Pattern.compile("^[a-zA-Z]{2}[d]{2}[d]{2}$");         //   1       XX-99-99
    		arrSC[1] = Pattern.compile("^[d]{2}[d]{2}[a-zA-Z]{2}$");         //   2       99-99-XX
    		arrSC[2] = Pattern.compile("^[d]{2}[a-zA-Z]{2}[d]{2}$");         //   3       99-XX-99
    		arrSC[3] = Pattern.compile("^[a-zA-Z]{2}[d]{2}[a-zA-Z]{2}$");     //   4       XX-99-XX
    		arrSC[4] = Pattern.compile("^[a-zA-Z]{2}[a-zA-Z]{2}[d]{2}$");     //   5       XX-XX-99
    		arrSC[5] = Pattern.compile("^[d]{2}[a-zA-Z]{2}[a-zA-Z]{2}$");     //   6       99-XX-XX
    		arrSC[6] = Pattern.compile("^[d]{2}[a-zA-Z]{3}[d]{1}$");      //   7       99-XXX-9
    		arrSC[7] = Pattern.compile("^[d]{1}[a-zA-Z]{3}[d]{2}$");         //   8       9-XXX-99
    		arrSC[8] = Pattern.compile("^[a-zA-Z]{2}[d]{3}[a-zA-Z]{1}$");     //   9       XX-999-X
    		arrSC[9] = Pattern.compile("^[a-zA-Z]{1}[d]{3}[a-zA-Z]{2}$");     //   10      X-999-XX
    		arrSC[10] = Pattern.compile("/^[a-zA-Z]{3}[d]{2}[a-zA-Z]{1}$");     //   11      XXX-99-X
    		arrSC[11] = Pattern.compile("/^[a-zA-Z]{1}[d]{2}[a-zA-Z]{3}$");     //   12      X-99-XXX
    		arrSC[12] = Pattern.compile("/^[d]{1}[a-zA-Z]{2}[d]{3}$");         //   13      9-XX-999
    		arrSC[13] = Pattern.compile("/^[d]{3}[a-zA-Z]{2}[d]{1}$");         //   14      999-XX-9	
     
    		//except licenseplates for diplomats
    		scUitz = Pattern.compile("^CD[ABFJNST][0-9]{1,3}$");              //for example: CDB1 of CDJ45
     
    		for(int i=0;i<arrSC.length;i++){
    			if (arrSC[i].matcher(licenseplate).matches()) {
    				return i+1;
    			}
    		}
    		if (scUitz.matcher(licenseplate).matches()) {
    			return 0;
    		}
    		return -1;
    	}
     
    	static public String FormatLicenseplate(String licenseplate, int sidecode) {
     
    		licenseplate = licenseplate.replace("-", "").toUpperCase();
     
    		if (sidecode <= 6) {
    				return licenseplate.substring(0, 2) + '-' + licenseplate.substring(2, 2) + '-' + licenseplate.substring(4, 2);
    		}
    		if (sidecode == 7 || sidecode == 9) {
    				return licenseplate.substring(0, 2) + '-' + licenseplate.substring(2, 3) + '-' + licenseplate.substring(5, 1);
    		}
    		if (sidecode == 8 || sidecode == 10) {
    				return licenseplate.substring(0, 1) + '-' + licenseplate.substring(1, 3) + '-' + licenseplate.substring(4, 2);
    		}
    		if (sidecode == 11 || sidecode == 14) {
    				return licenseplate.substring(0, 3) + '-' + licenseplate.substring(3, 2) + '-' + licenseplate.substring(5, 1);
    		}
    		if (sidecode == 12 || sidecode == 13) {
    				return licenseplate.substring(0, 1) + '-' + licenseplate.substring(1, 2) + '-' + licenseplate.substring(3, 3);
    		}
    		return licenseplate;
    	}
    1. Even een gekke vraag… ik probeer deze functie aan te roepen op mijn textarea, maar krijg het niet werkend… Heeft iemand hier de juiste syntax voor. Wat is wijsheid trouwens: onfocus, onblur of onchange?

  4. Dank je!

    Heb de code aangepast en gebruik het zelf in VBScript:

    Function GetLicenseplate(Licenseplate)
        Dim arrSC(9)
        Dim scUitz
     
        Licenseplate = UCase(Replace(Licenseplate, "-", ""))
     
    	arrSC(0) = "^[a-zA-Z]{2}[d]{2}[d]{2}$" ' 1 XX-99-99
    	arrSC(1) = "^[d]{2}[d]{2}[a-zA-Z]{2}$" ' 2 99-99-XX
    	arrSC(2) = "^[d]{2}[a-zA-Z]{2}[d]{2}$" ' 3 99-XX-99
    	arrSC(3) = "^[a-zA-Z]{2}[d]{2}[a-zA-Z]{2}$" ' 4 XX-99-XX
    	arrSC(4) = "^[a-zA-Z]{2}[a-zA-Z]{2}[d]{2}$" ' 5 XX-XX-99
    	arrSC(5) = "^[d]{2}[a-zA-Z]{2}[a-zA-Z]{2}$" ' 6 99-XX-XX
    	arrSC(6) = "^[d]{2}[a-zA-Z]{3}[d]{1}$" ' 7 99-XXX-9
    	arrSC(7) = "^[d]{1}[a-zA-Z]{3}[d]{2}$" ' 8 9-XXX-99
    	arrSC(8) = "^[a-zA-Z]{2}[d]{3}[a-zA-Z]{1}$" ' 9 XX-999-X
    	arrSC(9) = "^[a-zA-Z]{1}[d]{3}[a-zA-Z]{2}$" ' 10 X-999-XX
    	arrSC(10) = '^[a-zA-Z]{3}[d]{2}[a-zA-Z]{1}$" ' 11 XXX-99-X
    	arrSC(11) = '^[a-zA-Z]{1}[d]{2}[a-zA-Z]{3}$" ' 12 X-99-XXX
    	arrSC(12) = '^[d]{1}[a-zA-Z]{2}[d]{3}$" ' 13 9-XX-999
    	arrSC(13) = '^[d]{3}[a-zA-Z]{2}[d]{1}$" ' 14 999-XX-9	
    	
        'except licenseplates for diplomats
        scUitz = "^CD[ABFJNST][0-9]{1,3}$" 'for example: CDB1 of CDJ45
        
            For i = 0 To 13
                strPlate = CheckRegEx(Licenseplate, arrSC(i))
                If strPlate  "" Then
                    GetLicenseplate = FormatLicenseplate(strPlate, CStr((i + 1)))
                    Exit Function
                End If
            Next
     
            If CheckRegEx(Licenseplate, scUitz) Then
                GetLicenseplate = "CD"
                Exit Function
            End If
     
        GetLicenseplate = ""
     
    End Function
     
    Function CheckRegEx(Licenseplate, RegEx)
        Dim objRegExpr
        Set objRegExpr = New regexp
        objRegExpr.Pattern = RegEx
        objRegExpr.Global = True
        objRegExpr.IgnoreCase = True
        Dim colMatches
        Set colMatches = objRegExpr.Execute(Licenseplate)
        Dim objMatch
        For Each objMatch In colMatches
                CheckRegEx = objMatch.Value
        Next
        Set colMatches = Nothing
        Set objRegExpr = Nothing
    End Function
     
    Function FormatLicenseplate(Licenseplate, Sidecode)
        Licenseplate = UCase(Replace(Licenseplate, "-", ""))
            Select Case Sidecode
                Case "1", "2", "3", "4", "5", "6"
                    FormatLicenseplate = Mid(Licenseplate, 1, 2) & "-" & Mid(Licenseplate, 3, 2) & "-" & Mid(Licenseplate, 5, 2)
                Case "7", "9"
                    FormatLicenseplate = Mid(Licenseplate, 1, 2) & "-" & Mid(Licenseplate, 3, 3) & "-" & Mid(Licenseplate, 6, 1)
                Case "8", "10"
                    FormatLicenseplate = Mid(Licenseplate, 1, 1) & "-" & Mid(Licenseplate, 2, 3) & "-" & Mid(Licenseplate, 5, 2)
                Case "11", "14"
                    FormatLicenseplate = Mid(Licenseplate, 1, 3) & "-" & Mid(Licenseplate, 4, 2) & "-" & Mid(Licenseplate, 6, 1)
                Case "12", "13"
                    FormatLicenseplate = Mid(Licenseplate, 1, 1) & "-" & Mid(Licenseplate, 2, 2) & "-" & Mid(Licenseplate, 4, 3)
                Case Else
                    'No formatting with sidecode 'CD'
                    FormatLicenseplate = Licenseplate
            End Select
    End Function
  5. En een variant in Python:

    import re
    import string
     
    LICENSE_PLATE_RE = [
        re.compile("^([a-zA-Z]{2})([d]{2})([d]{2})$"), # 1 XX-99-99 11
        re.compile("^([d]{2})([d]{2})([a-zA-Z]{2})$"), # 2 99-99-XX 12
        re.compile("^([d]{2})([a-zA-Z]{2})([d]{2})$"), # 3 99-XX-99
        re.compile("^([a-zA-Z]{2})([d]{2})([a-zA-Z]{2})$"), # 4 XX-99-XX
        re.compile("^([a-zA-Z]{2})([a-zA-Z]{2})([d]{2})$"), # 5 XX-XX-99
        re.compile("^([d]{2})([a-zA-Z]{2})([a-zA-Z]{2})$"), # 6 99-XX-XX
        re.compile("^([d]{2})([a-zA-Z]{3})([d]{1})$"), # 7 99-XXX-9
        re.compile("^([d]{1})([a-zA-Z]{3})([d]{2})$"), # 8 9-XXX-99
        re.compile("^([a-zA-Z]{2})([d]{3})([a-zA-Z]{1})$"), # 9 XX-999-X 19
        re.compile("^([a-zA-Z]{1})([d]{3})([a-zA-Z]{2})$"), # 10 X-999-XX
        re.compile("^([a-zA-Z]{3})([d]{2})([a-zA-Z]{1})$"), # 11 XXX-99-X
        re.compile("^([a-zA-Z]{1})([d]{2})([a-zA-Z]{3})$"), # 12 X-99-XXX
        re.compile("^([d]{1})([a-zA-Z]{2})([d]{3})$"), # 13 9-XX-999
        re.compile("^([d]{3})([a-zA-Z]{2})([d]{1})$"), # 14 999-XX-9
        re.compile("^(CD[ABFJNST][0-9]{1,3})$") # 11 license plate for diplomats
    ]
     
    class LicensePlate():
        def __init__(self, number):
            self.normalized = re.sub('-', '', number.upper())
     
            for r in LICENSE_PLATE_RE:
                match = r.match(self.normalized)
                if match:
                    self.formatted = string.join(match.groups(), '-')
                    return None
     
            raise ValueError('Not a valid license plate')
     
        def __str__(self):
            return self.formatted

    De class LicensePlate heeft na instantiëren de variabelen normalized en formatted en geeft een ValueError exception bij een invalide kenteken plaat.

    1. hi,

      heel handig maar deze werkt niet of krijg ik niet aan het werk…
      Dank in ieder geval voor de post maar ik mis de formatted.
      Ook lastig dat het inspringen ontbreekt zeker in python …;-)

      hugo

  6. Aan gezien ik dit een zeer handige post vond wil ik wel de implementatie voor C# hier plaatsen:

    private static readonly Regex Sidecode1 = new Regex(@"^[a-zA-Z]{2}-[d]{2}-[d]{2}$", RegexOptions.Compiled); // XX-99-99
    private static readonly Regex Sidecode2 = new Regex(@"^[d]{2}-[d]{2}-[a-zA-Z]{2}$", RegexOptions.Compiled); // 99-99-XX
    private static readonly Regex Sidecode3 = new Regex(@"^[d]{2}-[a-zA-Z]{2}-[d]{2}$", RegexOptions.Compiled); // 99-XX-99
    private static readonly Regex Sidecode4 = new Regex(@"^[a-zA-Z]{2}-[d]{2}-[a-zA-Z]{2}$", RegexOptions.Compiled); // XX-99-XX
    private static readonly Regex Sidecode5 = new Regex(@"^[a-zA-Z]{2}-[a-zA-Z]{2}-[d]{2}$", RegexOptions.Compiled); // XX-XX-99
    private static readonly Regex Sidecode6 = new Regex(@"^[d]{2}-[a-zA-Z]{2}-[a-zA-Z]{2}$", RegexOptions.Compiled); // 99-XX-XX
    private static readonly Regex Sidecode7 = new Regex(@"^[d]{2}-[a-zA-Z]{3}-[d]{1}$", RegexOptions.Compiled); // 99-XXX-9
    private static readonly Regex Sidecode8 = new Regex(@"^[d]{1}-[a-zA-Z]{3}-[d]{2}$", RegexOptions.Compiled); // 9-XXX-99
    private static readonly Regex Sidecode9 = new Regex(@"^[a-zA-Z]{2}-[d]{3}-[a-zA-Z]{1}$", RegexOptions.Compiled); // XX-999-X
    private static readonly Regex Sidecode10 = new Regex(@"^[a-zA-Z]{1}-[d]{3}-[-a-zA-Z]{2}$", RegexOptions.Compiled); // X-999-XX
    private static readonly Regex Sidecode11 = new Regex(@"^[a-zA-Z]{3}-[d]{2}-[a-zA-Z]{1}$", RegexOptions.Compiled); // XXX-99-X
    private static readonly Regex Sidecode12 = new Regex(@"^[a-zA-Z]{1}-[d]{2}-[a-zA-Z]{3}$", RegexOptions.Compiled); // X-99-XXX
    private static readonly Regex Sidecode13 = new Regex(@"^[d]{1}-[a-zA-Z]{2}-[d]{3}$", RegexOptions.Compiled); // 9-XX-999
    private static readonly Regex Sidecode14 = new Regex(@"^[d]{3}-[a-zA-Z]{2}-[d]{1}$", RegexOptions.Compiled); // 999-XX-9
     
    /// 
    /// Determines whether [is valid licenseplate] [the specified input].
    /// 
    /// The input.
    /// 
    ///   true if [is valid licenseplate] [the specified input]; otherwise, false.
    /// 
    public static bool IsValidLicenseplate(this string input)
    {
        var expressions = new [] { Sidecode1, Sidecode2, Sidecode3, Sidecode4, Sidecode5, Sidecode6, Sidecode7, Sidecode8, Sidecode9, Sidecode10, Sidecode11, Sidecode12, Sidecode13, Sidecode14 };
        return expressions.Any(regex => regex.IsMatch(input));
    }
  7. Fijn om te gebruiken. Ik merk alleen bij de javascript variant dat bij heen en weer “tab’en” tussen de velden, de formatting wordt aangepast. Hebben meer mensen daar last van?

  8. hmm, in php is dit voldoende:

    function formatplate($kt){$mem="";$ktm="";for($i=0;$i=48&&ord($char)=65&&ord($mem)=48&&ord($mem)=65&&ord($char)<=122){$add="-";}$ktm.=$add.$char;$mem=$char;}return $ktm;}

    kan je aanroepen met $keteken=formatplate($kenteken); en je hebt streepjes op de juiste plaatsen.

    Hoe lang moet dit dan in andere talen zijn…..

      1. Helaas heb ik ook al wat kleine bugs gevonden, voornamelijk met 4 letters of cijfers achter elkaar. Deze zijn opgelost in wat meer code:

        function formatplate($kt){$kt=preg_replace("/[^0-9A-Za-z]/","",$kt);$mem="";$ktm="";$rem1=0;$rem2=0;
        for($i=0;$i=48&&ord($char)=65&&ord($mem)=2){$rem2++;}}
        if(ord($mem)>=48&&ord($mem)=65&&ord($char)=2){$rem2++;}}
        $ktm.=$add.$char;$mem=$char;
        if($rem1==8){$ktm=substr($ktm,0,strlen($ktm)-2)."-".substr($ktm,strlen($ktm)-2);$rem1=0;}
        if($rem2==8){$ktm=substr($ktm,0,strlen($ktm)-2)."-".substr($ktm,strlen($ktm)-2);$rem2=0;}
        }
        $ktm=str_replace("--","-",$ktm);
        return$ktm;
        }

        Deze functie kan je aanroepen met $geformateerd=formatplate($kenteken);

        Je kan deze testen op http://help.simbox.nl/logboek.png?s=50&p=1&t=test01 waarbij
        s = font size
        p = type (1 = met NL, 2 = zonder)
        t = tekst

        De pagina waarvoor ik deze gemaakt heb is te vinden op http://help.simbox.nl/logboek.htm en bevat een logboek-functie voor voertuigen met kenteken waarin met name de gemaakte kosten en kilometers kunnen worden berekend. Hierdoor worden zaken als kosten per kilometer en verbruik per kilometer op een eerlijke manier weergegeven.

    1. Uitgaande van de (eenvoudigere) regels dat er een streep komt tussen letters en cijfers, en dat 4 dezelfde letters of cijfer ook worden onderbroken met een cijfer kom ik tot deze, wat mij betreft eenvoudigere formatter:

      /**
       * Functie om kenteken uit database (zonder streepjes) om te zetten naar leesbaar formaat met
       * streepjes op de juiste plaats.
       * @param $kenteken Het niet geformateerde kenteken.
       * @return string Het geformatteerde kenteken.
       * @author Chris Flink 
       */
      function formatKenteken($kenteken) {
          // Match reeksen van letters en cijfer en sla deze op een een array $matches.
          $pattern = '/^([a-zA-Z]*)([0-9]*)([a-zA-Z]*)([0-9]*)/';
          preg_match($pattern, $kenteken, $matches);
       
          // Omdat er geen streep aan het begin moet houden we bij wat de eerste output is.
          $first = TRUE;
       
          // Het te retourneren kenteken wordt in deze string opgeslagen.
          $return = '';
       
          // We lopen door de matches 1 t/m 4, en voegen waar nodig waarden toe aan $return.
          for ($i=1; $i<5; $i++) {
              if (!empty($matches[$i])) {
                  if (!$first) {
                      $return .= '-';
                  }
                  // Als er 4 dezelfde karakters achter elkaar zijn worden deze gescheiden met een streep.
                  $return .= strlen($matches[$i]) == 4 ? substr($matches[$i], 0, 2) . "-" . substr($matches[$i], 2, 2) : $matches[$i];
                  $first = FALSE;
              }
          }
          // Return kenteken met streepjes in hoofdletters.
          return strtoupper($return);
      }

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *