Java正则提取地址块信息:排除额外行的匹配异常问题
Java正则提取地址字段的优化方案
问题背景
我原本用以下Java正则提取地址块信息:
\b(?!(?i)Doctor| )([^\s]*\b)[\n\r\s]+(\b[\S\s][^\d]*\b)[\s\S]+([0-9]{5})\s+([\D]*)
正常地址示例:
Doctor John DOE 123 dream road 12345 TOWN
对应的提取代码:
firstName = matcher.group(1).trim(); lastName = matcher.group(2).trim();
这个正则在正常格式下能正确提取名和姓,但当地址块包含额外行时(如下示例),提取的姓会错误匹配为DOE Country Hospital:
Doctor John DOE Country Hospital 123 dream road 12345 TOWN
我需要能分别提取名、姓、地址行1(可选)、地址行2、邮编、城镇这几个字段,但找不到合适的正则模式。
优化后的正则方案
针对地址块的结构特征(姓名行以Doctor开头,邮编为固定5位数字,最后一行是邮编+城镇),调整后的正则如下:
(?i)^Doctor\s+([^\s]+)\s+([^\n\r]+)\n\r?((?:[^\n\r]+\n\r?)?)[^\d]*?(\b\d{5})\s+([^\n\r]+)$
正则各部分解释
(?i)^Doctor\s+:忽略大小写匹配开头的Doctor,后跟任意空白字符([^\s]+):捕获名(姓名行中第一个空白前的非空白内容)\s+([^\n\r]+):捕获姓(姓名行剩余的非换行内容)\n\r?:兼容Windows/Unix格式的换行符((?:[^\n\r]+\n\r?)?):捕获可选的地址行1(非换行内容+换行,整个组为可选)[^\d]*?:非贪婪模式匹配地址行2前的任意非数字内容,避免过度匹配(\b\d{5}):捕获5位邮编\s+([^\n\r]+)$:捕获城镇(邮编后的非换行内容,直到文本结尾)
Java提取代码示例
import java.util.regex.Matcher; import java.util.regex.Pattern; public class AddressExtractor { public static void main(String[] args) { String regex = "(?i)^Doctor\\s+([^\\s]+)\\s+([^\\n\\r]+)\\n\\r?((?:[^\\n\\r]+\\n\\r?)?)[^\\d]*?(\\b\\d{5})\\s+([^\\n\\r]+)$"; Pattern pattern = Pattern.compile(regex); // 正常地址测试 String normalAddr = "Doctor John DOE\n123 dream road \n12345 TOWN"; Matcher matcher = pattern.matcher(normalAddr); if (matcher.find()) { System.out.println("正常地址提取结果:"); System.out.println("名:" + matcher.group(1).trim()); System.out.println("姓:" + matcher.group(2).trim()); System.out.println("地址行1(可选):" + (matcher.group(3).isEmpty() ? "无" : matcher.group(3).trim())); System.out.println("地址行2:" + normalAddr.substring(matcher.end(3), matcher.start(4)).trim()); System.out.println("邮编:" + matcher.group(4).trim()); System.out.println("城镇:" + matcher.group(5).trim()); } // 含额外行的地址测试 String extraLineAddr = "Doctor John DOE\nCountry Hospital\n123 dream road \n12345 TOWN"; matcher = pattern.matcher(extraLineAddr); if (matcher.find()) { System.out.println("\n含额外行的地址提取结果:"); System.out.println("名:" + matcher.group(1).trim()); System.out.println("姓:" + matcher.group(2).trim()); System.out.println("地址行1(可选):" + matcher.group(3).trim()); System.out.println("地址行2:" + extraLineAddr.substring(matcher.end(3), matcher.start(4)).trim()); System.out.println("邮编:" + matcher.group(4).trim()); System.out.println("城镇:" + matcher.group(5).trim()); } } }
提取说明
- 地址行1对应可选的额外行(如示例中的
Country Hospital),无额外行时显示为“无” - 地址行2通过截取地址行1结束到邮编开始的内容获取,确保无论是否有额外行都能正确提取
内容的提问来源于stack exchange,提问作者anakin59490
相关产品推荐
相关产品推荐

