Java中如何基于正则表达式掩码生成精准匹配语句?
问题描述
我有100个类似如下格式的正则表达式掩码:
Service - (?<status>Start|End) (?<etl>\w*) - (?<date>[0-9-]{10})(?: - (?<outcome>.*))?
用这些掩码匹配文本后,我会提取分组数据,生成一条用于精确搜索的"闭合"语句(搜索时不能用正则,否则可能匹配到其他开头类似但数据不同的语句),比如从Service - Start Foo - 2024-03-09提取数据后,要生成Service - End Foo - 2024-03-09这样的搜索语句。
请问如何在Java中实现:用提取到的分组数据替换正则掩码中的对应部分,生成目标搜索语句?
示例代码(未实现核心方法)
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Main { public static void main(String[] args) { List<String> rowsData = new ArrayList<>(); List<String> masks = new ArrayList<>(); loadData(rowsData); loadMasks(masks); for (var data : rowsData) { String mask = findMask(data, masks); if (mask != null) { Map<String, String> values = getValues(data, mask); var endSentence = prepareOutcome(mask, values); for (var endData : rowsData) { if (endData.contains(endSentence)) { System.out.println("End found at " + rowsData.indexOf(endData)); return; } } System.out.println("End not found"); } } System.out.println("Finish Searching"); } private static String prepareOutcome(String mask, Map<String, String> values) { // TODO: 需要实现这里的逻辑 var stringToSearch = "Service - End Foo - 2024-03-09"; return stringToSearch; } private static void loadMasks(List<String> masks) { masks.add("Service - (?<status>Start|End) (?<etl>\\w*) - (?<date>[0-9-]{10})(?: - (?<outcome>.*))?"); //... 其他掩码 } private static void loadData(List<String> rowsData) { //... 其他数据 rowsData.add("Service - Start Foo - 2024-03-09"); rowsData.add("Service - Start Foo - 2024-03-10"); rowsData.add("Service2 - Foo something Bar - Start"); // 其他数据 rowsData.add("Service - End Foo - 2024-03-10 - Outcome KO"); rowsData.add("Service2 - Foo something Bar - End"); rowsData.add("Service - End Foo - 2024-03-09 - Outcome OK"); } private static String findMask(String data, List<String> masks) { // 这里简化返回了固定掩码,实际需要遍历匹配 return "Service - (?<status>Start|End) (?<etl>\\w*) - (?<date>[0-9-]{10})(?: - (?<outcome>.*))?"; } private static Map<String, String> getValues(String data, String mask) { // 这里简化返回了固定值,实际需要用正则提取分组 Map<String, String> values = new HashMap<>(); values.put("status", "Start"); values.put("etl", "Foo"); values.put("date", "2024-03-09"); return values; } }
可行实现方案
核心思路是把正则掩码转换成模板字符串,替换分组占位符的同时处理可选分组逻辑,具体实现如下:
private static String prepareOutcome(String mask, Map<String, String> values) { // 1. 将正则中的命名捕获分组转换为模板占位符:(?<name>...) → {name} String template = mask.replaceAll("\\(\\?<([a-zA-Z0-9]+)>[^)]+\\)", "\\{$1\\}"); // 2. 处理非捕获可选分组:移除无对应值的可选片段 template = template.replaceAll("\\(\\?:(.*?)\\)\\?", match -> { String segment = match.group(1); // 检查片段内的占位符是否有对应值 boolean hasValidValue = segment.matches(".*\\{([a-zA-Z0-9]+)\\}.*") && values.containsKey(segment.replaceAll("[^a-zA-Z0-9]", "")); return hasValidValue ? segment : ""; }); // 3. 替换占位符为实际值,强制将status替换为End for (Map.Entry<String, String> entry : values.entrySet()) { String value = "status".equals(entry.getKey()) ? "End" : entry.getValue(); template = template.replace("{" + entry.getKey() + "}", value); } return template.trim(); }
实现说明
- 第一步把正则语法的命名分组转换成模板占位符,将掩码从正则格式转为可填充的模板格式
- 第二步处理可选分组:对于
(?: - {outcome})?这类可选片段,只有当outcome有提取值时才保留该部分,否则直接移除 - 第三步替换占位符时,强制将
status字段的值改为End,以生成对应Start记录的End搜索语句,其他字段直接使用提取到的数据
测试该方法时,传入示例中的掩码和分组数据,会返回Service - End Foo - 2024-03-09,符合需求。
内容的提问来源于stack exchange,提问作者ilSaul
相关产品推荐
相关产品推荐

