Number Plate Golf: Parsing

6

2

See Also: Recognition

Introduction

You've now been taken off the speed camera development team (let's face it, your code is nowhere near production code standards) and are now working on a program to extract information about the car from the number plates. Of course, you've caught the code golf bug and want to write the program in as few bytes as possible.

Challenge

Given a valid, British number plate, display information about the car's registration.

You only have to support number plates registered between 2001 and 2051 (inclusive).

Internet access is disallowed.

The input will be given as a string.

Number Plates

British number plates are ordered like so:

Area code

A table with all of the area code mnemonics which you need to support can be found here.

For the letter X, you only need to output Personal Export due to multiple areas being covered by the same mnemonic.

You must output the DVLA office name.

Age Identifier

Similarly, a table with all of the age identifiers which you need to support can be found here.

If the identifier is in the range Y to 50 inclusive, you must output:

1/3/[Year] to 31/8/[Year]

Likewise, if the identifier is in the range 51 to 00 inclusive, you must output:

1/9/[Year] to [28/29]/2/[Year + 1]

You should support leap years.

Examples

WK94 FRS

Truro, 1/9/2044 to 28/2/2045

CB16 BTD

Bangor, 1/3/2016 to 31/8/2016

BD51 SMR

Birmingham, 1/9/2011 to 29/2/2012

XAY EEA

Personal Export, 1/3/2001 to 31/8/2001

Scoring

The shortest code in bytes wins

Beta Decay

Posted 2016-08-19T17:37:51.673

Reputation: 21 478

Are we allowed to fetch online data? – R. Kap – 2016-08-19T23:15:25.600

@R.Kap No, you should not – Beta Decay – 2016-08-19T23:31:58.127

The output for BD51 ANY should read Birmingham, 1/9/2001 to 28/2/2002, I think you meant BD61 for leap year demo purposes? – YetiCGN – 2016-08-26T15:31:08.783

Not quite Area 51... – mbomb007 – 2016-08-26T15:51:53.633

1One side effect of this challenge: Every time I see a car or motorcycle with GB plates, I try to decode them in my head. :-) – YetiCGN – 2016-08-29T15:46:33.680

Answers

4

Ruby, 629 bytes

s=gets
p=c=0
'PETeRborOuGh
NORWich
IPSwicH
BIRMiNGHam
CARdiff
SWANsea
BAngOr
CHEsTer
SHREWsbURY
CHELmSFOrd
NOTTInGHAm
LInCOlN
MAIDStone
BRIgHtON
BOURNEMoUth
PORTSMoUth
ISLE OF WIGHt
PORtSmOUtH
BOREHAMwoOD
NORTHAmPton
WIMBLeDoN
BOREHAMwOoD
SIdcup
MANChESTer
NEWCAstle
STOcKtON
oXFOrd
PReStON
CArlISlE
ReADIng
GLAsGoW
EDINBUrGh
DUNdEe
ABERDEen
INvErNEsS
WORcESTer
EXeTeR
TRUro
BRiStoL
PERSONAL eXPOrt
LeEds
SHEFFiElD
BEVERLEY'.split($/).map{|w|c<s[0,2].to_i(35)&&p=w;d=0;w.bytes{|b|d+=d+b/95};c+=d}
y=(?1+s[2,9]).to_i-1
puts p.capitalize+", 1/%d/20%02d to %d/%d/20%02d"%[z=3+y%100/50*6,1+y%=50,z<4?31:y%4==2?29:28,(z+5)%12,1+y+z/9]

The first two letters are interpreted as a base 35 number and then looked up to find the correct town. The quantity of addresses assigned to each town is encoded (run-length encoding) in the captialization of each town in binary, where uppercase=0 and lowercase=1.

In order to handle the Y age indicator for the first half of 2001, a 1 is prepended to the age. Thus 1 Y is interpreted by .to_i as 1, and 1 02 is interpreted as 102. 1 is subtracted (to handle the wraparound for 2050) and taken modulo 100 to decide which half of the year we are in. It is then taken modulo 50 (and the 1 added on again) to find the year.

Level River St

Posted 2016-08-19T17:37:51.673

Reputation: 22 049

Nice! You're lucky most of the names are only one word. However, "Isle of wight" is incorrectly capitalized. ;-) – YetiCGN – 2016-08-23T17:07:22.177

Your code contains errors, unfortunately. In addition to the minor mistake of not capitalizing the "wight" in "Isle of Wight", for the test case in Birmingham it yields "28/2/2012" instead of "29/2/2012", because 2012 is a leap year. – YetiCGN – 2016-08-26T14:22:05.630

Sorry! It's actually the example that's wrong. Your code correctly accounts for leap years. – YetiCGN – 2016-08-26T15:30:26.673

3

PHP, 1044 800 757 bytes

The script is added to a PHAR (PHP archive) and compressed with gzip to shrink it from 1044 to 800 bytes. Further optimization took the original code down to 994 bytes, which then as a Phar is 757 bytes. Takes the license plate string as the first argument like php u.phar BD51 SMR (actually the latter part is read as "second argument", but useless garbage anyway for this challenge).

Download the uklic.phar file for this answer

This is the script before compression:

<?$o=[X=>'Personal export',B=>Birmingham,E=>Chelmsford,M=>Manchester,O=>Oxford,R=>Reading,V=>Worcester,A=>['A-N'=>Peterborough,'O-U'=>Norwich,'V-Y'=>Ipswich],C=>['A-O'=>Cardiff,'P-V'=>Swansea,WXY=>Bangor],D=>['A-K'=>Chester,'L-Y'=>Shrewsbury],F=>['A-P'=>Nottingham,'R-Y'=>Lincoln],G=>['A-O'=>Maidstone,'P-Y'=>Brighton],H=>['A-J'=>Bournemouth,'K-Y'=>Portsmouth,W=>'Isle of Wight'],K=>['A-L'=>Borehamwood,'M-Y'=>Northampton],L=>['A-J'=>Wimbledon,'K-T'=>Borehamwood,'U-Y'=>Sidcup],N=>['A-O'=>Newcastle,'P-Y'=>Stockton],P=>['A-T'=>Preston,'U-Y'=>Carlisle],S=>['A-J'=>Glasgow,'K-O'=>Edinburgh,'P-T'=>Dundee,UVW=>Aberdeen,XY=>Inverness],W=>['A-J'=>Exeter,KL=>Truro,'M-Y'=>Bristol],Y=>['A-K'=>Leeds,'L-U'=>Sheffield,'V-Y'=>Beverley]];$p=$argv[1];$a=$o[$p{0}];$z=$a;if(count($a)>1){foreach($a as$r=>$d){if(preg_match("/[$r]/",$p{1})){$z=$d;}}}$n=$p{2}.$p{3};$y=$n+($n==Y);if($y==0)$y=50;$h=$y&&$n<51;$y%=50;$x=$y+1;printf('%s, 1/%s/20%02d to %s/20%02d',$z,$h?3:9,$y,$h?'31/8':28+!($x%4).'/2',$h?$y:$x);

The DVLA Office lookup is a simple map with a string if the first character of the license plate is enough to identify the office and an array if we need the second character. The character range is then matched with a simple regexp.

The code for the date range is quite easy except for the two edge cases "Y" and "00", which can't be calculated. Y is cast to integer and added a 1, in case the input is an integer. That's how we get 2001 for Y. 00 is accounted for by modulo arithmetic.

This is the slightly better readable version:

<?
$o = [
  X => 'Personal export',
  B => Birmingham,
  E => Chelmsford,
  M => Manchester,
  O => Oxford,
  R => Reading,
  V => Worcester,
  A => ['A-N' => Peterborough, 'O-U' => Norwich, 'V-Y' => Ipswich],
  C => ['A-O' => Cardiff, 'P-V' => Swansea, WXY => Bangor],
  D => ['A-K' => Chester, 'L-Y' => Shrewsbury],
  F => ['A-P' => Nottingham, 'R-Y' => Lincoln],
  G => ['A-O' => Maidstone, 'P-Y' => Brighton],
  H => ['A-J' => Bournemouth, 'K-Y' => Portsmouth, W => 'Isle of Wight'],
  K => ['A-L' => Borehamwood, 'M-Y' => Northampton],
  L => ['A-J' => Wimbledon, 'K-T' => Borehamwood, 'U-Y' => Sidcup],
  N => ['A-O' => Newcastle, 'P-Y' => Stockton],
  P => ['A-T' => Preston, 'U-Y' => Carlisle],
  S => ['A-J' => Glasgow, 'K-O' => Edinburgh, 'P-T' => Dundee, UVW => Aberdeen, XY => Inverness],
  W => ['A-J' => Exeter, 'KL' => Truro, 'M-Y' => Bristol],
  Y => ['A-K' => Leeds, 'L-U' => Sheffield, 'V-Y' => Beverley]
];
$p=$argv[1];

$a=$o[$p{0}];
$z=$a;
if (count($a)-1) {
    foreach($a as $r => $d) {
        if (preg_match('/['.$r.']/', $p{1})) {$z=$d; }
    }
}
$n=$p{2}.$p{3};
$y=$n+($n==Y);
if ($y==0) {
    $y=50;
}
$h=$y&&$n<51;
$y%=50;
$x=$y+1;
printf('%s, 1/%s/20%02d to %s/20%02d',$z,$h?3:9,$y,$h?'31/8':28+!($x%4).'/2',$h?$y:$x);

Updates:

  1. Seriously trimmed down the date calculation section and made use of printf, replaced is_array($a) with `count($a)>1
  2. Optimized the Phar bootstrapping

YetiCGN

Posted 2016-08-19T17:37:51.673

Reputation: 941

Great idea with the string arguments :D – Beta Decay – 2016-08-19T22:30:57.643

Thanks! :-) Actually, with the magic of PHAR, I can compress it down to 800 bytes exactly. But I don't know if that's within the spirit of the competition.

– YetiCGN – 2016-08-19T22:42:27.390

If it's a compression library, you can use it – Beta Decay – 2016-08-19T22:49:12.567