3

I need to check the U.K postcode against a list.

The U.K postcode is of a standard format but the list only contains the outward section that I need to check against.

The list contains a series of outward postcode with also some data relating to this outward postcode, so for example

AL     St Albans
B      Birmingham
BT     Belfast
TR     Taunton
TR21    Taunton X
TR22    Taunton Y

My aim is that when I get a postcode, for example B20 7TP, I can search and find Birmingham.

Any ideas??

The question is different to the ones referred to as possible answers, but in my case I need to check a full postcode against just the outward postcode.

wakthar
  • 720
  • 1
  • 8
  • 21

2 Answers2

1

If you have the whole postcode and only want to use the outcode, remove the last three characters and use what remains. All postcodes end with the pattern digit-alpha-alpha, so removing those characters will give the outcode; any string that does not fit that pattern or that does not give a valid outcode after removing that substring is not a valid postcode. (Source)


If you're willing to take on an external (and Internet-based) dependency, you could look at using something like https://postcodes.io, in particular the outcodes section of that API. I have no affiliation with postcodes.io; I just found it after a Google.

Per the documentation, /outcodes will return

  • the outcode
  • the eastings
  • the northings
  • the andministrative counties under the code
  • the district/unitary authories under the code
  • the administrative/electoral areas under the code
  • the WGS84 logitude
  • the WGS84 latitude
  • the countries included in the code
  • the parish/communities in the code

For reference, a call to /outcodes/TA1 returns:

{
  "status": 200,
  "result": {
    "outcode": "TA1",
    "longitude": -3.10297767924529,
    "latitude": 51.0133987332761,
    "northings": 124359,
    "eastings": 322721,
    "admin_district": [
      "Taunton Deane"
    ],
    "parish": [
      "Taunton Deane, unparished area",
      "Bishop's Hull",
      "West Monkton",
      "Trull",
      "Comeytrowe"
   ],
    "admin_county": [
      "Somerset"
    ],
    "admin_ward": [
      "Taunton Halcon",
      "Bishop's Hull",
      "Taunton Lyngford",
      "Taunton Eastgate",
      "West Monkton",
      "Taunton Manor and Wilton",
      "Taunton Fairwater",
      "Taunton Killams and Mountfield",
      "Trull",
      "Comeytrowe",
      "Taunton Blackbrook and Holway"
    ],
    "country": [
      "England"
    ]
  }
}

If you have the whole postcode, the /postcodes endpoint will return considerably more detailed information which I will not include here, but it does include the outcode and the incode as separate fields.

I would, of course, recommend caching the results of any call to a remote API.

Richard Ward
  • 360
  • 3
  • 14
0

Build a regular expression from the list of known codes. Pay attention that the order of known codes in the regular expression matters. You need to use longer codes before shorter codes.

private void button1_Click(object sender, EventArgs e)
{
    textBoxLog.Clear();

    var regionList = BuildList();
    var regex = BuildRegex(regionList.Keys);

    TryMatch("B20 7TP", regionList, regex);
    TryMatch("BT1 1AB", regionList, regex);
    TryMatch("TR21 1AB", regionList, regex);
    TryMatch("TR0 00", regionList, regex);
    TryMatch("XX123", regionList, regex);
}

private static IReadOnlyDictionary<string, string> BuildList()
{
    Dictionary<string, string> result = new Dictionary<string, string>();

    result.Add("AL", "St Albans");
    result.Add("B", "Birmingham");
    result.Add("BT", "Belfast");
    result.Add("TR", "Taunton");
    result.Add("TR21", "Taunton X");
    result.Add("TR22", "Taunton Y");

    return result;
}

private static Regex BuildRegex(IEnumerable<string> codes)
{
    // Sort the code by length descending so that for example TR21 is sorted before TR and is found by regex engine
    // before the shorter match
    codes = from code in codes
            orderby code.Length descending
            select code;

    // Escape the codes to be used in the regex
    codes = from code in codes
            select Regex.Escape(code);

    // create Regex Alternatives
    string codesAlternatives = string.Join("|", codes.ToArray());

    // A regex that starts with any of the codes and then has any data following
    string lRegExSource = "^(" + codesAlternatives + ").*";

    return new Regex(lRegExSource, RegexOptions.IgnoreCase | RegexOptions.Singleline);
}


/// <summary>
/// Try to match the postcode to a region
/// </summary>
private bool CheckPostCode(string postCode, out string identifiedRegion, IReadOnlyDictionary<string, string> regionList, Regex regex)
{
    // Check whether we have any match at all
    Match match = regex.Match(postCode);
    bool result = match.Success;

    if (result)
    {
        // Take region code from first match group
        // and use it in dictionary to get region name
        string regionCode = match.Groups[1].Value;
        identifiedRegion = regionList[regionCode];
    }
    else
    {
        identifiedRegion = "";
    }

    return result;
}

private void TryMatch(string code, IReadOnlyDictionary<string, string> regionList, Regex regex)
{
    string region;

    if (CheckPostCode(code, out region, regionList, regex))
    {
        AppendLog(code + ": " + region);
    }
    else
    {
        AppendLog(code + ": NO MATCH");
    }
}

private void AppendLog(string log)
{
    textBoxLog.AppendText(log + Environment.NewLine);
}

Produces this output:

B20 7TP: Birmingham
BT1 1AB: Belfast
TR21 1AB: Taunton X
TR0 00: Taunton
XX123: NO MATCH

For your information, the regex built here is ^(TR21|TR22|AL|BT|TR|B).*

NineBerry
  • 26,306
  • 3
  • 62
  • 93