Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
DiscussionsAccessExcelInfoPathOutlookPowerPointPublisherWord
DirectoryUser Groups
Related Topics
Outlook ExpressInternet ExplorerWindowsMS Server ProductsMore Topics ...

MS Office Forum / Excel / Programming / September 2007

Tip: Looking for answers? Try searching our database.

Full proof UK postcode validation

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Ed Peters - 17 Sep 2007 22:25 GMT
Hi all,

I trying to do UK postcode validation.

>From a previous post by 'Toppers'  I've got the code below. It looks
good however it fails if a postcode of, for example,  xxxx 4at.

Does anyone have a better solution?

Thanks,

Ed

Sub MyTest()
   ValidatePostCode "WX2 1BA"
End Sub

Sub ValidatePostCode(Byval PostCode as String)
'
' Validate UK Post Code
'
Dim v As Variant
Dim Outer As String, Inner As String
Dim invalid As Boolean

v = Split(PostCode, " ")
If UBound(v) = 0 Then
  MsgBox "Post code " & PostCode & " does not contain a blank"
  Exit Sub
End If

Outer = UCase(Trim(v(0)))
Inner = UCase(Trim(v(1)))
'
' Validate inner code .....
'
invalid = False
If Len(Inner) <> 3 Then
   invalid = True
Else
   If Left(Inner, 1) Like "[0-9]" Then
      If Mid(Inner, 2, 1) Like "[A-Z]" And Mid(Inner, 3, 1) Like "[A-
Z]" Then
      Else
      invalid = True
      End If
   Else
      invalid = True
   End If
End If
If invalid Then
   MsgBox "Inner code " & Inner & " is invalid"
   Exit Sub
End If
'
' Validate Outer code .....
'
invalid = False
Select Case Len(Outer)

Case Is = 2
   If Left(Outer, 1) Like "[A-Z]" And Right(Outer, 1) Like "[0-9]"
Then
   Else
       invalid = True
   End If
Case Is = 3
   If Left(Outer, 1) Like "[A-Z]" And Right(Outer, 1) Like "[0-9]" _
   And (Mid(Outer, 2, 1) Like "[A-Z]" Or Mid(Outer, 2, 1) Like
"[0-9]") Then
   Else
       invalid = True
   End If
Case Is = 4
   If Left(Outer, 1) Like "[A-Z]" And Right(Outer, 1) Like "[A-Z]" _
   And (Mid(Outer, 2, 1) Like "[A-Z]" Or Mid(Outer, 2, 1) Like
"[0-9]") _
   And (Mid(Outer, 3, 1) Like "[A-Z]" Or Mid(Outer, 3, 1) Like
"[0-9]") Then
   Else
       invalid = True
   End If
Case Else
   invalid = True
End Select

If invalid Then
    MsgBox "Outer code " & Outer & " is invalid"
    Exit Sub
End If

MsgBox "Post Code " & PostCode & " is valid"
Bob Phillips - 17 Sep 2007 23:36 GMT
Sub ValidatePostCode(ByVal PostCode As String)
'
' Validate UK Post Code
'
Dim v As Variant
Dim Outer As String, Inner As String
Dim invalid As Boolean

v = Split(PostCode, " ")
If UBound(v) = 0 Then
  MsgBox "Post code " & PostCode & " does not contain a blank"
  Exit Sub
End If

Outer = UCase(Trim(v(0)))
Inner = UCase(Trim(v(1)))
'
' Validate inner code .....
'
invalid = False
If Len(Inner) <> 3 Then
   invalid = True
Else
   If Left(Inner, 1) Like "[0-9]" Then
      If Mid(Inner, 2, 1) Like "[A-Z]" And Mid(Inner, 3, 1) Like "[A-Z]"
Then
      Else
      invalid = True
      End If
   Else
      invalid = True
   End If
End If
If invalid Then
   MsgBox "Inner code " & Inner & " is invalid"
   Exit Sub
End If
'
' Validate Outer code .....
'
invalid = False
Select Case Len(Outer)

Case Is = 2
   If Left(Outer, 1) Like "[A-Z]" And Right(Outer, 1) Like "[0-9]" Then
   Else
       invalid = True
   End If
Case Is = 3
   If Left(Outer, 1) Like "[A-Z]" And Right(Outer, 1) Like "[0-9]" _
   And (Mid(Outer, 2, 1) Like "[A-Z]" Or Mid(Outer, 2, 1) Like "[0-9]")
Then
   Else
       invalid = True
   End If
Case Is = 4
   If Left(Outer, 1) Like "[A-Z]" And Right(Outer, 1) Like "[0-9]" _
   And (Mid(Outer, 2, 1) Like "[A-Z]" Or Mid(Outer, 2, 1) Like "[0-9]") _
   And (Mid(Outer, 3, 1) Like "[A-Z]" Or Mid(Outer, 3, 1) Like "[0-9]")
Then
   Else
       invalid = True
   End If
Case Else
   invalid = True
End Select

If invalid Then
    MsgBox "Outer code " & Outer & " is invalid"
    Exit Sub
End If

MsgBox "Post Code " & PostCode & " is valid"

End Sub

Signature

---
HTH

Bob

(there's no email, no snail mail, but somewhere should be gmail in my addy)

> Hi all,
>
[quoted text clipped - 88 lines]
>
> MsgBox "Post Code " & PostCode & " is valid"
Peter T - 18 Sep 2007 09:08 GMT
Hi Bob,

Not sure about the following

these London codes return false -ve
W1A 1HP
EC1A 1BB

this returns false +ve
A1A1 1AA

UK postcode rules -
http://www.mailsorttechnical.com/frequentlyaskedquestions.cfm
"
Format-Example     Postcode
"A" indicates an alphabetic character and "N" indicates a numeric character.
AN NAA     M1 1AA
ANN NAA     M60 1NW
AAN NAA     CR2 6XH
AANN NAA     DN55 1PT
ANA NAA     W1A 1HP
AANA NAA     EC1A 1BB

The postcode GIR 0AA was issued historically and does not confirm to current
rules on valid Postcode formats - it is however still in use for Alliance &
Leicester Girobank Plc in Bootle.

These conventions are liable to change in the future if operationally
required.
"

I tried to fault Rick's but couldn't <g>, except the anomaly GIR 0AA.

Regards,
Peter T

> Sub ValidatePostCode(ByVal PostCode As String)
> '
[quoted text clipped - 172 lines]
> >
> > MsgBox "Post Code " & PostCode & " is valid"
Bob Phillips - 18 Sep 2007 09:45 GMT
I am not sure about the whole co Peter, I just made the identified problem
work :-).

I recall an earlier post that Jamie Collins was in that tried to produce a
catch-all solution.

Signature

---
HTH

Bob

(there's no email, no snail mail, but somewhere should be gmail in my addy)

> Hi Bob,
>
[quoted text clipped - 213 lines]
>> >
>> > MsgBox "Post Code " & PostCode & " is valid"
Rick Rothstein (MVP - VB) - 17 Sep 2007 23:40 GMT
I am pretty sure this function will work...

Function ValidatePostCode(ByVal PostCode As String) As Boolean
 Dim Parts() As String
 Parts = Split(PostCode)
 ValidatePostCode = (Parts(1) Like "#[A-Z][A-Z]") And _
                   ((Parts(0) Like "[A-Z]#") Or _
                    (Parts(0) Like "[A-Z]#[0-9A-Z]") Or _
                    (Parts(0) Like "[A-Z][A-Z]#") Or _
                    (Parts(0) Like "[A-Z][A-Z]#[0-9A-Z]"))
End Function

It returns True or False (rather than posting a MessageBox) which you can
use in your own code to decide on how to proceed.

Rick

> Hi all,
>
[quoted text clipped - 88 lines]
>
> MsgBox "Post Code " & PostCode & " is valid"
Rick Rothstein (MVP - VB) - 18 Sep 2007 10:31 GMT
Well, I am not completely sure of my code anymore. I think it proofs the
vast majority of them, but I also think there are some exceptions to the
rule I used to create my code. I'll try looking into this in more detail
later on today.

Rick

>I am pretty sure this function will work...
>
[quoted text clipped - 101 lines]
>>
>> MsgBox "Post Code " & PostCode & " is valid"
Rick Rothstein (MVP - VB) - 18 Sep 2007 15:22 GMT
Okay, my original function appears to be correct except for GIR 0AA which
is some kind of historically special Post Code. Here is my function,
modified to accept that special Post Code...

Function ValidatePostCode(ByVal PostCode As String) As Boolean
 Dim Parts() As String
 Parts = Split(PostCode)
 ValidatePostCode = PostCode = "GIR 0AA" Or _
                   ((Parts(1) Like "#[A-Z][A-Z]") And _
                   ((Parts(0) Like "[A-Z]#") Or _
                    (Parts(0) Like "[A-Z]#[0-9A-Z]") Or _
                    (Parts(0) Like "[A-Z][A-Z]#") Or _
                    (Parts(0) Like "[A-Z][A-Z]#[0-9A-Z]")))
End Function

Now, to add one clarification.... my function only checks to make sure the
"shape" of the Post Code is correct, not that the Post Code being checked is
actually in use. From this standpoint, the function should continue to work,
given what it does, for any new Post Codes that may be added in the future.

Rick

> Well, I am not completely sure of my code anymore. I think it proofs the
> vast majority of them, but I also think there are some exceptions to the
[quoted text clipped - 108 lines]
>>>
>>> MsgBox "Post Code " & PostCode & " is valid"
Doug Glancy - 18 Sep 2007 04:22 GMT
Ed,

You could look into using a regular expression, although it seems to be one
that is hard to pin down:

http://regexlib.com/REDetails.aspx?regexp_id=260

hth,

Doug

> Hi all,
>
[quoted text clipped - 88 lines]
>
> MsgBox "Post Code " & PostCode & " is valid"
Mike H - 18 Sep 2007 14:14 GMT
If this is entirely the wrong approach it's because regular expressions are
very new ground to me but this hasn't failed yet. I don't know wheteher the
OP was just testing but WX2 1BA from the original post is invalid according
to this site

http://www.royalmail.com/portal/rm/addressfinder;jsessionid=C2XA1VZTG1KROFB2IGVU
NZQUHRA0UQ2K?catId=400145&pageId=pcaf_a_search&gear=postcode


Still testing though.

Option Explicit
Sub UK_Postcodes()
Dim RegExp As Object, Collection As Object, RegMatch As Object
Dim Myrange As Range, C As Range, Outstring As String
   Set RegExp = CreateObject("vbscript.RegExp")
   With RegExp
       .Global = False
       .Pattern = "(?:(?:A[BL]|B[ABDHLNRST]?|" _
               & "C[ABFHMORTVW]|D[ADEGHLNTY]|E[CHNX]?|F[KY]|G[LUY]?|" _
               & "H[ADGPRSUX]|I[GMPV]|JE|K[ATWY]|L[ADELNSU]?|M[EKL]?|" _
               & "N[EGNPRW]?|O[LX]|P[AEHLOR]|R[GHM]|S[AEGKLMNOPRSTWY]?|" _
               & "T[ADFNQRSW]|UB|W[ACDFNRSV]?|YO|ZE)" _
               & "\d(?:\d|[A-Z])? \d[A-Z]{2})"
   End With
   Set Myrange = ActiveCell
       Outstring = ""
       Set Collection = RegExp.Execute(ActiveCell.Value)
       For Each RegMatch In Collection
           Outstring = Outstring & RegMatch
       Next
     
      If ActiveCell.Value <> "" And ActiveCell.Value = Outstring Then
           MsgBox "Valid UK Postcode"
      Else
           MsgBox "Invalid UK Postcode"
      End If
   Set Collection = Nothing
   Set RegExp = Nothing
   Set Myrange = Nothing
End Sub

Mike

> Ed,
>
[quoted text clipped - 99 lines]
> >
> > MsgBox "Post Code " & PostCode & " is valid"
Peter T - 18 Sep 2007 17:24 GMT
That looks very good indeed. Do you or anyone know how or where to verify
the authenticity of that pattern, ideally from Royal Mail, in order to use
it with confidence.

Regards,
Peter T

> If this is entirely the wrong approach it's because regular expressions are
> very new ground to me but this hasn't failed yet. I don't know wheteher the
> OP was just testing but WX2 1BA from the original post is invalid according
> to this site

http://www.royalmail.com/portal/rm/addressfinder;jsessionid=C2XA1VZTG1KROFB2
IGVUNZQUHRA0UQ2K?catId=400145&pageId=pcaf_a_search&gear=postcode

> Still testing though.
>
[quoted text clipped - 30 lines]
>
> Mike

<snip>
Ed Peters - 18 Sep 2007 21:10 GMT
> That looks very good indeed. Do you or anyone know how or where to verify
> the authenticity of that pattern, ideally from Royal Mail, in order to use
[quoted text clipped - 52 lines]
>
> - Show quoted text -

Wow what a response!

Great coding!

How would I take the True of False value and insert some text from the
code below.

I've tried, which does not work.

If ValidatePostCode = False Then
ValidatePostCode = "Invalid"
Else
ValidatePostCode = "Valid"
End If

Function ValidatePostCode(ByVal PostCode As String) As Boolean
 Dim Parts() As String
 Parts = Split(PostCode)
 ValidatePostCode = PostCode = "GIR 0AA" Or _
                   ((Parts(1) Like "#[A-Z][A-Z]") And _
                   ((Parts(0) Like "[A-Z]#") Or _
                    (Parts(0) Like "[A-Z]#[0-9A-Z]") Or _
                    (Parts(0) Like "[A-Z][A-Z]#") Or _
                    (Parts(0) Like "[A-Z][A-Z]#[0-9A-Z]")))
End Function

Thanks,

ED
Rick Rothstein (MVP - VB) - 18 Sep 2007 22:38 GMT
> > Function ValidatePostCode(ByVal PostCode As String) As Boolean
>
[quoted text clipped - 8 lines]
> ValidatePostCode = "Valid"
> End If

There are a couple of things wrong with the way you structured your code (as
shown above)...

The first thing wrong with your code is that you need to pass the PostCode
into the function (otherwise the function doesn't know what to test).  I'm
not sure where you are getting your PostCode from within your program. If it
were from a TextBox (named, say, TextBox1 for this example, then your
If-Then statement should look like this...

If ValidatePostCode(TextBox1.Text) Then

Notice I did not set it equal to True or False. Why? Because the function
already returns either True or False, so asking if True = True or False =
False is redundant. That means, then, that the code directly under the
If-Then statement should be for the "True condition" (the "Valid" for you
example code) and the code after the Else statement should be for the "False
condition" (the "Invalid" in your example code).

The second thing wrong with your code is that you are trying to assign
String values to the function... you can't do that. In you have to use a
variable with a name different from the function, say,
ResultFromValidatePostCodeFunction. This would mean your example code above
should look like this instead...

If ValidatePostCode(TextBox1.Text) Then
 ResultFromValidatePostCodeFunction = "Valid"
Else
 ResultFromValidatePostCodeFunction = "Invalid"
End If

Of course, a variable named ResultFromValidatePostCodeFunction is kind of
extreme, but I used that to give you the general idea of how to approach
using the function.

Okay, now that that is straightened out, I have modified my ValidatePostCode
function to validate the PostCode Area as well as the "shape" of the Post
Code itself (which is all the original function did). Of course, this makes
the function less general than my original function meaning if any PostCode
Areas are added or removed UK Mail System in the future, the function will
need to be changed to account for addition and/or removal. Anyway, you can
stay with my original function or use the modified function below, your
choice.

Rick

Function ValidatePostCode(ByVal PostCode As String) As Boolean
 Dim Parts() As String
 PostCode = UCase$(PostCode)
 Parts = Split(PostCode)
 If PostCode = "GIR 0AA" Or PostCode = "SAN TA1" Or _
   (Parts(1) Like "#[A-Z][A-Z]" And _
   (Parts(0) Like "[A-Z]#" Or _
    Parts(0) Like "[A-Z]#[0-9A-Z]" Or _
    Parts(0) Like "[A-Z][A-Z]#" Or _
    Parts(0) Like "[A-Z][A-Z]#[0-9A-Z]")) Then
   ValidatePostCode = (Parts(0) Like "[BEGLMSW]#*" Or _
                       Parts(0) Like "A[BL]#*" Or _
                       Parts(0) Like "B[ABDHLNRST]#*" Or _
                       Parts(0) Like "C[ABFHMORTVW]#*" Or _
                       Parts(0) Like "D[ADEGHLNTY]#*" Or _
                       Parts(0) Like "E[CHNX]#*" Or _
                       Parts(0) Like "F[KY]#*" Or _
                       Parts(0) Like "G[LU]#*" Or _
                       Parts(0) Like "H[ADGPRSUX]#*" Or _
                       Parts(0) Like "I[GPV]#*" Or _
                       Parts(0) Like "K[ATWY]#*" Or _
                       Parts(0) Like "L[ADELNSU]#*" Or _
                       Parts(0) Like "M[EKL]#*" Or _
                       Parts(0) Like "N[EGNPRW]#*" Or _
                       Parts(0) Like "O[LX]#*" Or _
                       Parts(0) Like "P[AEHLOR]#*" Or _
                       Parts(0) Like "R[GHM]#*" Or _
                       Parts(0) Like "S[AEGKLMNOPRSTWY]#*" Or _
                       Parts(0) Like "T[ADFNQRSW]#*" Or _
                       Parts(0) Like "W[ACDFNRSV]#*" Or _
                       Parts(0) Like "UB#*" Or _
                       Parts(0) Like "YO#*" Or _
                       Parts(0) Like "ZE#*")
 End If
End Function
Ed Peters - 19 Sep 2007 08:52 GMT
On 18 Sep, 22:38, "Rick Rothstein \(MVP - VB\)"
<rickNOSPAMn...@NOSPAMcomcast.net> wrote:
> > > Function ValidatePostCode(ByValPostCodeAs String) As Boolean
>
[quoted text clipped - 89 lines]
>   End If
> End Function

Thanks Rick for Shape coding. Looks good.

Thanks also for your detailed explaination of my coding. However I'm
still trying to work out how to pass the Postcode into the function.
I'm using cells to get postcode, eg, in cell B1 I'm putting
=validatepostcode(a1) which then returns True / False and this is
where I need the text string "valid" or "Invalid".

Cheers

Ed
Ed Peters - 19 Sep 2007 09:10 GMT
> On 18 Sep, 22:38, "Rick Rothstein \(MVP - VB\)"
>
[quoted text clipped - 106 lines]
>
> - Show quoted text -

Hi ,

I think I've sorted it now, using an idea from another post,  see code
below . I've removed the as boolean for the function.

Public Function ValidatePostCode(ByVal PostCode As String)
 Dim Parts() As String
 Dim invalid As Boolean
 Parts = Split(PostCode)

 invalid = False

 If ValidatePostCode = PostCode = "GIR 0AA" Or _
                   ((Parts(1) Like "#[A-Z][A-Z]") And _
                   ((Parts(0) Like "[A-Z]#") Or _
                    (Parts(0) Like "[A-Z]#[0-9A-Z]") Or _
                    (Parts(0) Like "[A-Z][A-Z]#") Or _
                    (Parts(0) Like "[A-Z][A-Z]#[0-9A-Z]"))) Then

                    Else
                     invalid = True
                    End If
If invalid Then

   ValidatePostCode = "Invalid postcode"
   Exit Function
   Else
   ValidatePostCode = "Valid postcode"
End If

End Function

Ed
Rick Rothstein (MVP - VB) - 19 Sep 2007 10:13 GMT
> I think I've sorted it now, using an idea from another post,  see code
> below . I've removed the as boolean for the function.
[quoted text clipped - 25 lines]
>
> End Function

Okay, I missed the part where you wanted to use the function up at the
spreadsheet level as opposed to running it wholly within the macro. In your
modification above, you don't really need to create a new variable to handle
the Valid/Invalid selection...

Function ValidatePostCode(ByVal PostCode As String)
 Dim Parts() As String
 PostCode = UCase$(PostCode)
 Parts = Split(PostCode)
 If PostCode = "GIR 0AA" Or PostCode = "SAN TA1" Or _
   (Parts(1) Like "#[A-Z][A-Z]" And _
   (Parts(0) Like "[A-Z]#" Or _
    Parts(0) Like "[A-Z]#[0-9A-Z]" Or _
    Parts(0) Like "[A-Z][A-Z]#" Or _
    Parts(0) Like "[A-Z][A-Z]#[0-9A-Z]")) Then
   ValidatePostCode = (Parts(0) Like "[BEGLMSW]#*" Or _
                       Parts(0) Like "A[BL]#*" Or _
                       Parts(0) Like "B[ABDHLNRST]#*" Or _
                       Parts(0) Like "C[ABFHMORTVW]#*" Or _
                       Parts(0) Like "D[ADEGHLNTY]#*" Or _
                       Parts(0) Like "E[CHNX]#*" Or _
                       Parts(0) Like "F[KY]#*" Or _
                       Parts(0) Like "G[LU]#*" Or _
                       Parts(0) Like "H[ADGPRSUX]#*" Or _
                       Parts(0) Like "I[GPV]#*" Or _
                       Parts(0) Like "K[ATWY]#*" Or _
                       Parts(0) Like "L[ADELNSU]#*" Or _
                       Parts(0) Like "M[EKL]#*" Or _
                       Parts(0) Like "N[EGNPRW]#*" Or _
                       Parts(0) Like "O[LX]#*" Or _
                       Parts(0) Like "P[AEHLOR]#*" Or _
                       Parts(0) Like "R[GHM]#*" Or _
                       Parts(0) Like "S[AEGKLMNOPRSTWY]#*" Or _
                       Parts(0) Like "T[ADFNQRSW]#*" Or _
                       Parts(0) Like "W[ACDFNRSV]#*" Or _
                       Parts(0) Like "UB#*" Or _
                       Parts(0) Like "YO#*" Or _
                       Parts(0) Like "ZE#*")
 End If
 If ValidatePostCode Then
   ValidatePostCode = "Valid"
 Else
   ValidatePostCode = "Invalid"
 End If
End Function

Notice, all I did was check to see if ValidatePostCode was True and, if it
was, set the function name to "Valid"; otherwise, set it to "Invalid". This
works because the default value for any variable in VBA (the function name
act like a variable within function; that is why you assign the return value
to it) is 0, the numerical equivalent for False. So, ValidatePostCode is
equal to 0 (False) unless it passes the test within the If-Then block where
it will be set to True. Hence, you can use the value of ValidatePostCode
directly after the If-Then block to reset its value to "Valid" or "Invalid".

Rick
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.