检查英国邮编是否有效

3

我需要检查英国邮编是否包含在一个列表中。

英国邮编有一个标准的格式,但这个列表只包含我需要检查的外向部分。

该列表包含一系列外向邮政编码,还包含与此外向邮政编码相关的一些数据,例如:

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

我的目的是,当我得到一个邮政编码,比如B20 7TP,我可以搜索并找到伯明翰。

有什么想法吗?

这个问题与可能的答案不同,但在我的情况下,我需要将完整的邮政编码与只有外向邮政编码进行匹配。


1
那么如果你得到邮政编码 TR21 1AB,你想匹配 Taunton 还是 Taunton X?同样地,邮政编码 BT1 1AB 应该如何知道要匹配 Belfast 而不是 Birmingham - Jamiec
如果给定邮编TR21 1AB,则需要匹配Taunton X,同样,BT1 1AB需要匹配Belfast。谢谢。 - wakthar
TR不是Taunton而是Truro。 - NineBerry
1
@wakthar 知道这一点。挑战在于根据您的要求正确定义该逻辑。 - Jamiec
1
@wakthar 你可以使用在重复问题链接中找到的正则表达式匹配组。 - Chris Pickford
2个回答

1
如果您有完整的邮政编码,只想使用前缀部分,请删除最后三个字符并使用剩余的部分。所有邮政编码都以数字-字母-字母的模式结尾,因此删除这些字符将给出前缀部分;任何不符合该模式或在删除该子字符串后未能提供有效前缀部分的字符串均不是有效的邮政编码。(来源
如果您愿意承担一个外部(基于互联网的)依赖项,您可以考虑使用类似https://postcodes.io的东西,特别是该API的outcodes部分。我与postcodes.io没有任何关系;我只是在Google之后发现它。
根据文档,/outcodes将返回:
- 邮政编码前缀 - 东向坐标 - 北向坐标 - 代码下的行政县 - 代码下的区/自治市 - 代码下的行政/选区 - WGS84经度 - WGS84纬度 - 代码包含的国家 - 代码中的教区/社区
作为参考,对/outcodes/TA1的调用返回:
{
  "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"
    ]
  }
}

如果您拥有完整的邮编,/postcodes终端将返回更详细的信息,但我不会在此包含,但它包括单独的outcode和incode字段。

当然,我建议缓存对远程API的任何调用结果。


毫无疑问,这是正确的做法 - 但并不是问题的答案。 - Jamiec
@Jamiec,我添加了更多细节;你看到我漏掉的东西了吗? - Richard Ward

0

从已知代码列表中构建正则表达式。注意,已知代码在正则表达式中的顺序很重要。您需要在较短的代码之前使用较长的代码。

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);
}

生成以下输出:

B20 7TP:伯明翰
BT1 1AB:贝尔法斯特
TR21 1AB:陶顿 X
TR0 00:陶顿
XX123:无匹配项

请注意,此处构建的正则表达式为 ^(TR21|TR22|AL|BT|TR|B).*


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接