如何用Java从位置随机的URL中提取两位国家代码(无需硬编码)
如何在Java中不硬编码国家代码提取URL中的两位国家代码
这问题挺常见的,我之前处理多区域URL解析需求时也碰过类似场景,给你分享几个实用的思路,完全不用硬编码所有国家代码就能搞定:
思路一:提取候选片段 + 匹配ISO标准国家代码集合
核心逻辑是:先从URL里找出所有可能的两位字母片段,再用Java自带的ISO标准国家代码集合做校验,筛选出有效的国家代码。
步骤拆解
- 获取ISO 3166-1的两位国家代码全集:Java的
Locale.getISOCountries()方法直接返回所有标准两位国家代码,不用自己手动维护列表。 - 用正则或字符串拆分提取URL中不同位置的两位字母候选(域名后缀、路径中的xx-xx格式、路径单独段等)。
- 对比候选和标准集合,筛选出有效代码,同时可以结合语言代码集合排除误判(比如把语言代码当成国家代码)。
代码示例
import java.util.*; import java.util.regex.*; import java.util.stream.Collectors; public class CountryCodeExtractor { public static List<String> extractCountryCodesFromUrl(String url) { // 获取标准两位国家代码集合(转小写方便匹配) Set<String> validCountryCodes = Arrays.stream(Locale.getISOCountries()) .map(String::toLowerCase) .collect(Collectors.toSet()); // 获取标准两位语言代码集合(用于排除误判) Set<String> languageCodes = Arrays.stream(Locale.getISOLanguages()) .map(String::toLowerCase) .collect(Collectors.toSet()); List<String> result = new ArrayList<>(); String lowerUrl = url.toLowerCase(); // 1. 匹配域名后缀的国家代码(如.uk) Pattern domainSuffixPattern = Pattern.compile("\\.([a-z]{2})(?:/|$)"); Matcher domainMatcher = domainSuffixPattern.matcher(lowerUrl); while (domainMatcher.find()) { String code = domainMatcher.group(1); if (validCountryCodes.contains(code)) { result.add(code.toUpperCase()); } } // 2. 匹配路径中的xx-xx格式(如/de-de,取第二个代码) Pattern langCountryPattern = Pattern.compile("/([a-z]{2})-([a-z]{2})(?:/|$)"); Matcher langCountryMatcher = langCountryPattern.matcher(lowerUrl); while (langCountryMatcher.find()) { String countryCode = langCountryMatcher.group(2); if (validCountryCodes.contains(countryCode)) { result.add(countryCode.toUpperCase()); } } // 3. 匹配路径中单独的两位字母段(可选,需谨慎) Pattern standalonePattern = Pattern.compile("/([a-z]{2})(?:/|$)"); Matcher standaloneMatcher = standalonePattern.matcher(lowerUrl); while (standaloneMatcher.find()) { String code = standaloneMatcher.group(1); // 是国家代码且不是语言代码时加入结果 if (validCountryCodes.contains(code) && !languageCodes.contains(code)) { result.add(code.toUpperCase()); } } // 去重并保持顺序 return new ArrayList<>(new LinkedHashSet<>(result)); } public static void main(String[] args) { System.out.println(extractCountryCodesFromUrl("www.abc.com.uk/services")); // [UK] System.out.println(extractCountryCodesFromUrl("www.prices.com/de-de")); // [DE] System.out.println(extractCountryCodesFromUrl("www.customers.com/fr-fr/services")); // [FR] } }
思路说明
- 用
Locale类的API获取标准代码,完全避免硬编码,后续ISO标准更新时Java会同步维护。 - 分场景匹配不同位置的候选,减少误判;比如xx-xx格式中优先取第二个代码作为国家代码(符合常见的语言-国家命名规范)。
- 最后去重,避免同一个URL中出现多次相同的国家代码。
思路二:结构化解析URL + 标准代码校验
如果URL格式比较规范,用Java的URL类解析结构后再处理会更稳妥,避免正则的一些边缘情况。
步骤拆解
- 用
java.net.URL类解析URL的主机、路径等部分。 - 主机部分拆分后缀,提取最后两位字母匹配国家代码。
- 路径部分拆分各个段,分别处理xx-xx格式和单独两位字母段。
- 同样用标准代码集合做校验筛选。
代码示例
import java.net.MalformedURLException; import java.net.URL; import java.util.*; import java.util.stream.Collectors; public class CountryCodeUrlParser { public static List<String> extractCountryCodes(String url) throws MalformedURLException { Set<String> validCountryCodes = Arrays.stream(Locale.getISOCountries()) .map(String::toLowerCase) .collect(Collectors.toSet()); Set<String> languageCodes = Arrays.stream(Locale.getISOLanguages()) .map(String::toLowerCase) .collect(Collectors.toSet()); List<String> result = new ArrayList<>(); URL parsedUrl = new URL(url); // 处理主机部分的国家代码 String host = parsedUrl.getHost().toLowerCase(); String[] hostParts = host.split("\\."); if (hostParts.length >= 2) { String lastPart = hostParts[hostParts.length - 1]; if (lastPart.length() == 2 && validCountryCodes.contains(lastPart)) { result.add(lastPart.toUpperCase()); } } // 处理路径部分 String path = parsedUrl.getPath().toLowerCase(); if (!path.isEmpty()) { String[] pathSegments = path.split("/"); for (String segment : pathSegments) { if (segment.contains("-")) { String[] langCountry = segment.split("-"); if (langCountry.length == 2) { String countryCode = langCountry[1]; if (countryCode.length() == 2 && validCountryCodes.contains(countryCode)) { result.add(countryCode.toUpperCase()); } } } else if (segment.length() == 2) { if (validCountryCodes.contains(segment) && !languageCodes.contains(segment)) { result.add(segment.toUpperCase()); } } } } // 去重 return new ArrayList<>(new LinkedHashSet<>(result)); } public static void main(String[] args) throws MalformedURLException { System.out.println(extractCountryCodes("www.abc.com.uk/services")); // [UK] System.out.println(extractCountryCodes("www.prices.com/de-de")); // [DE] System.out.println(extractCountryCodes("www.customers.com/fr-fr/services")); // [FR] } }
思路说明
- 结构化解析URL更清晰,比如主机部分的拆分不会受到路径中字符的干扰。
- 同样依赖
Locale的标准代码,无需硬编码。 - 对于路径段的处理更直观,适合URL格式比较规范的场景。
注意事项
- 重叠代码处理:有些两位代码既是语言代码也是国家代码(比如
fr是法语也是法国的国家代码),如果业务上需要区分,可以结合URL的上下文(比如域名后缀、路径层级)做进一步判断,或者让业务逻辑处理这类模糊情况。 - 大小写兼容:统一转成小写或大写后再匹配,避免URL大小写不一致导致的漏判。
- 边缘情况:比如
co.uk这类域名,直接取最后两位uk即可,因为uk本身是标准国家代码,无需额外处理二级域名。
内容的提问来源于stack exchange,提问作者linuxman
相关产品推荐
相关产品推荐

