Wednesday, April 15, 2009

Australian Postcode Validation

I was recently porting and updating some old Pascal postcode validation to C# and thought i'd stick it up here.

To tell the truth, the Pascal code is more concise. Pascal, VB, Ruby etc have means to test a range of values in a single case statement. Unfortunately C# doesn't provide for this contingency, hence the "fall through's" in the case blocks.

Anyway, maybe someone might find this useful as there are a few "interesting" situations with the ACT and NSW.



 1     public static string GetState(string postCode) {
 2       if (!IsValidPostCodeFormat(postCode))
 3         return "";
 4
 5       switch (postCode[0]) {
 6         case '5': return "SA";             // SA:  5000-5999
 7         case '3':
 8         case '8': return "VIC";            // VIC: 3000-3999, 8000-8999
 9         case '4':
10         case '9': return "QLD";            // QLD: 4000-4999, 9000-9999
11         case '6': return "WA";             // WA:  6000-6999
12         case '7': return "TAS";            // TAS: 7000-7999
13         case '1': return "NSW";            // NSW: 1000-1999
14
15         case '0':
16           switch (postCode[1]) {
17             case '8':
18             case '9': return "NT";         // NT:  0800-0999
19             case '2': return "ACT";        // ACT: 0200-0299
20             default: return "";
21           }
22
23         case '2':
24           int tmp = Int32.Parse(postCode);
25           if ((tmp >= 2600 && tmp <= 2618) || (tmp >= 2900 && tmp <= 2920))
26             return "ACT";                  // ACT: 2600-2618, 2900-2920
27           else if ((tmp >= 2000 && tmp <= 2599) || (tmp >= 2619 && tmp <= 2898)
28                                                 || (tmp >= 2921 && tmp <= 2999))
29             return "NSW";                  // NSW: 2000-2599, 2619-2898, 2921-2999
30           else return "";
31
32         default: return "";
33       }
34     }
35
36     private static bool IsValidPostCodeFormat(string postCode) {
37       int tmp;
38       if (String.IsNullOrEmpty(postCode) || postCode.Length != 4 
39                                          || !Int32.TryParse(postCode, out tmp))
40         return false;
41
42       return true;
43     }
44




1 comment:

rhinoman said...

Hi,

great work, I converted your code to real SQL Server type syntax, works great.

Graeme

DECLARE @testpostcode NVARCHAR(4);
DECLARE @state NVARCHAR(4);

set @testpostcode = '2621';

SELECT @state =
CASE
-- // SA: 5000-5999
WHEN SUBSTRING(@testpostcode, 1,1) = '5' THEN 'SA'
-- // VIC: 3000-3999, 8000-8999
WHEN SUBSTRING(@testpostcode, 1,1) = '3' OR SUBSTRING(@testpostcode, 1,1) = '8' THEN 'VIC'
-- // QLD: 4000-4999, 9000-9999
WHEN SUBSTRING(@testpostcode, 1,1) = '4' OR SUBSTRING(@testpostcode, 1,1) = '9' THEN 'QLD'
-- // WA: 6000-6999
WHEN SUBSTRING(@testpostcode, 1,1) = '6' THEN 'WA'
-- // TAS: 7000-7999
WHEN SUBSTRING(@testpostcode, 1,1) = '7' THEN 'TAS'
-- // NSW: 1000-1999
WHEN SUBSTRING(@testpostcode, 1,1) = '1' THEN 'NSW'
-- checks for postcodes starting with 0
WHEN ((SUBSTRING(@testpostcode, 1,1) = '0') AND
-- // NT: 0800-0999
(SUBSTRING(@testpostcode, 2,1) = '8' OR SUBSTRING(@testpostcode, 2,1) = '9')) THEN 'NT'
-- // ACT: 0200-0299
WHEN ((SUBSTRING(@testpostcode, 1,1) = '0') AND
(SUBSTRING(@testpostcode, 2,1) = '2')) THEN 'ACT'

-- // checks for postcodes in the crazy ACT NSW formatting!!
WHEN SUBSTRING(@testpostcode, 1,1) = '2' AND
-- // ACT: 2600-2618, 2900-2920
((CAST(SUBSTRING(@testpostcode, 1,4) AS INT) >= 2600 AND (CAST(SUBSTRING(@testpostcode, 1,4) AS INT) <= 2618)) OR
(CAST(SUBSTRING(@testpostcode, 1,4) AS INT) >= 2900 AND CAST(SUBSTRING(@testpostcode, 1,4) AS INT) <= 2920))
THEN 'ACT'

WHEN SUBSTRING(@testpostcode, 1,1) = '2' AND
-- // NSW: 2000-2599, 2619-2898, 2921-2999
((CAST(SUBSTRING(@testpostcode, 1,4) AS INT) >= 2000 AND (CAST(SUBSTRING(@testpostcode, 1,4) AS INT) <= 2599)) OR
(CAST(SUBSTRING(@testpostcode, 1,4) AS INT) >= 2619 AND CAST(SUBSTRING(@testpostcode, 1,4) AS INT) <= 2898) OR
(CAST(SUBSTRING(@testpostcode, 1,4) AS INT) >= 2921 AND CAST(SUBSTRING(@testpostcode, 1,4) AS INT) <= 2999))
THEN 'NSW2'


ELSE 'n/a'
END ;


SELECT @state, 'Postcode base' + ' ' + SUBSTRING(@testpostcode, 1,4);