0

I am unfamiliar with the "Like" notation, # and * used where they have been, I would like a bit of validation here. This piece of code on the web and would like to know if it does as it should. The code, plus some some comments I have included:

 Function ValidPostCode(ByVal PostCode As String) As Boolean
  '----------------------------------------------------------
   ' Deals with the postcodes of the form:
   'AN NAA
   'ANN NAA
   'AAN NAA
   'ANA NAA
   'AANA NAA
   'AANN NAA
   'has issues with spaces and obscure entries like "England".
    'Notes from Wiki::
 'As all formats end with 9AA, the first part of a postcode can easily be extracted by ignoring the last three characters
 'Areas with only single-digit districts: BR, FY, HA, HD, HG, HR, HS, HX,      JE, LD, SM, SR, WC, WN, ZE (although WC is always subdivided by a further letter, e.g. WC1A).
 'Areas with only double-digit districts: AB, LL, SO.
 'Areas with a district '0' (zero): BL, BS, CM, CR, FY, HA, PR, SL, SS (BS is the only area to have both a district 0 and a district 10).
'The following central London single-digit districts have been further divided by inserting a letter after the digit and before the space: EC1–EC4 (but not EC50), SW1, W1, WC1, WC2, and part of E1 (E1W), N1 (N1C and N1P), NW1 (NW1W) and SE1 (SE1P).
  'The letters QVX are not used in the first position.
'The letters IJZ are not used in the second position.
  'The only letters to appear in the third position are ABCDEFGHJKPSTUW when the structure starts with A9A.
   'The only letters to appear in the fourth position are ABEHMNPRVWXY when the structure starts with AA9A.
    'The final two letters do not use the letters CIKMOV, so as not to resemble digits or each other when hand-written.
 'Post code sectors are one of ten digits: 0 to 9 with 0 only used once 9 has been used in a post town, save for Croydon and Newport (see above).

 '-----------------------------------------------------------
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-9ABCDEFGHJKSTUW]" Or _
     Parts(0) Like "[A-Z][A-Z]#" Or Parts(0) Like "[A-Z][A-Z]#[0-9ABEHMNPRVWXY]")) Then
     ValidPostCode = ((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]#[AMNRVY]" 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#*") And _
                      Parts(1) Like "*#[!CIKMOV][!CIKMOV]")
Else
    ValidPostCode = False
End If
End Function

Please, if anyone can help and possibly explain the code thoroughly I would be extremely grateful.

Thank you

apaderno
  • 28,547
  • 16
  • 75
  • 90
  • 1
    Using regular expressions may be easier. – Nathan_Sav Oct 31 '16 at 12:28
  • 1
    Here is a link the Microsoft documentation: [VBA Like Operator](https://msdn.microsoft.com/en-us/library/office/gg251796.aspx). The VBA docs are a gold mine of information and worth bookmarking. – David Rushton Oct 31 '16 at 13:42

2 Answers2

0

Something like this using VB Script Regular Expressions

Function VALIDATE_PCODE(strPostCode As String) As Boolean

Dim R As RegExp

Set R = New RegExp

'   Validate AB## and AC# post codes

With R
    .MultiLine = False
    .IgnoreCase = True
    .Global = True
    .Pattern = "^AB\d{1,2} |AC\d{1} "   ' can use [0-9] here as  \d
End With

VALIDATE_PCODE = R.Test(strPostCode)

Set R = Nothing

End Function

EDIT

Using what you've supplied, you could build the pattern something like the below.

Function Validate_PostCode(strPostCode As String) As Boolean

Const cstSingleDigit As String = _
    "BR,FY,HA,HD,HG,HR,HS,HX,JE,LD,SM,SR,WC,WN,ZE"
Const cstDoubleDigit As String = _
    "AB,LL,SO"

Dim arrTemp() As String
Dim strRegExPattern As String
Dim intCounter As Integer
Dim rgeRegExp As RegExp

'   Build the Reg Ex pattern

strRegExPattern = "^"

arrTemp = Split(cstSingleDigit, ",")

For intCounter = 0 To UBound(arrTemp)

    strRegExPattern = strRegExPattern & _
                        IIf(intCounter > 0, "|", "") & _
                        arrTemp(intCounter) & "\d{1} "

Next intCounter

Erase arrTemp

arrTemp = Split(cstDoubleDigit, ",")

For intCounter = 0 To UBound(arrTemp)

    strRegExPattern = strRegExPattern & "|" & _
                        arrTemp(intCounter) & "\d{2} "

Next intCounter

Set rgeRegExp = New RegExp

rgeRegExp.Global = True
rgeRegExp.IgnoreCase = True
rgeRegExp.Pattern = strRegExPattern

Validate_PostCode = rgeRegExp.Test(strPostCode)

End Function
Nathan_Sav
  • 8,466
  • 2
  • 13
  • 20
  • I'm assuming that this is for the UK - [this answer](http://stackoverflow.com/a/164994/4088852) gives the officially supplied regex. – Comintern Oct 31 '16 at 12:43
  • Great guys, thanks. Do we have an up-to-date RegEx supplied by the government? Do we know of one...? Anyone? DO we know where to get one? –  Oct 31 '16 at 13:19
0

I generally use this Reg Ex to validate the postcodes (the pattern can always be improved, but this hasn't failed me yet) - will return either the postcode or a #VALUE error.

'Returns the postcode or #VALUE error when used as worksheet function.
'Use the 'OR alternatives if being called from within VBA - will return TRUE/FALSE on matches.
Public Function ValidatePostCode(strData As String) As String 'OR Boolean
    Dim RE As Object, REMatches As Object

    Set RE = CreateObject("vbscript.regexp")
    With RE
        .MultiLine = False
        .Global = False
        .IgnoreCase = True
        .Pattern = "^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$"
    End With

    Set REMatches = RE.Execute(strData)

    ValidatePostCode = REMatches(0) 'OR REMatches.Count > 0

End Function
Darren Bartrup-Cook
  • 18,362
  • 1
  • 23
  • 45
  • Sorry Darren, the last line seems to return a runtime error-Invalid procedure or argument? Which seems very odd? –  Oct 31 '16 at 14:26
  • 1
    That's weird - working perfectly on mine.... actually, just checked as I generally just use it as a worksheet function. Seems if called from within VBA it throws the error on invalid postcodes: `?ValidatePostCode("AB1 0AAz")`. This is because `REMatches` returns a count of 0 on no match so you can't look at the first match on that - change that last line to `ValidatePostCode = REMatches.Count > 0` and the function return type to `Boolean` - you'll get TRUE/FALSE responses. I've updated my code with the VBA alternative. – Darren Bartrup-Cook Oct 31 '16 at 14:45
  • There a number of postcodes that don't fit this pattern (correct postcodes, but the above says otherwise), the ones I have found are: W1D 4RW, W1D 4SG, W1D 4SN, W1D 5DF ,W1D 5EQ W1D 5ND...how would I adjust the pattern to correct for these. –  Oct 31 '16 at 16:40
  • Can't we just get rid of the West End - too many shows there anyway :p Either that or try one of the patterns in @Cominterns link below. The post by @Chisel seems to deal with the W1 postcodes: `([A-PR-UWYZ]([A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y])?|[0-9]([0-9]|[A-HJKPSTUW])?) ?[0-9][ABD-HJLNP-UW-Z]{2})` – Darren Bartrup-Cook Oct 31 '16 at 17:06