
本教程旨在详细讲解如何使用java正则表达式从复杂的日志字符串中高效地提取`key=value`对,并将其存储到`map
在日常的系统运维和开发中,我们经常需要处理包含大量信息的日志文件。这些日志通常以非结构化或半结构化的文本形式存在,其中包含着许多关键的KEY=VALUE对。从这些复杂的字符串中准确地提取所需信息,特别是当值本身可能包含空格、引号甚至嵌套结构时,是一个常见的挑战。
本教程将展示如何利用Java的正则表达式(Regex)功能,有效地从一个典型的复杂日志字符串中解析出所有的KEY=VALUE对,并将其组织成一个Map<String, String>对象。
考虑以下日志字符串示例,其中包含多种类型的KEY=VALUE对:
String logString = "DC696,"/xi/ajax/remoting/call/plaincall/adhocReportBuilderControllerProxy.getRortList.dwr","2222-11-10 08:32:22,351 PLV=REQ CIP=9.9.9.7 CMID=syairp CMN=""Dub Airport Corporation Limited"" SN=sfv4_APM180885. DPN=dbPool66HFT01 UID=3862D04108 UN=91F6025D47F01D IUID=1931 LOC=en_GB EID=""EVENT-UNKNOWN-UNKNOWN-ob55abe0118-201110083217-396080"" AGN=""[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35]"" RID=REQ-[7274545] MTD=POST URL=""/xi/ajax/remoting/call/plaincall/adhocRrtBuilderCoollerProxy.getRtList.dwr"" RQT=2835 MID=ADIN PID=ADMIN PQ=ADIN_PAGE SUB=0 MEM=2331036 CPU=2410 UCPU=2300 SCPU=110 FRE=10 FWR=0 NRE=2281 NWR=218 SQLC=43 SQLT=142 RPS=200 SID=60826A3FAB005A8A9B930177C5******.pc6bc1029 GID=e262dde6d0e040070b58afd4c8 HSID=ddc665538db779508d3213c0bb63bcb1c49fe8236d5f0884ae975915728e61 CSL=CRITICAL CCON=0 CSUP=0 CLOC=0 CEXT=0 CREM=0 STK={""n"":""/xi/ajax/remoting/call/plaincall/adhocReportBuilderControllerProxy.getrtList.dwr"",""i"":1,""t"":2835,""slft"":2679,""sub"":[{""n"":""SQL:select * from sfv4_HOUA180885.REPORT_DEF WHERE REPORT_DEF_ID IN (SELECT REPORT_DEF_ID FROM sfv4_HA80885.REPORT_DTASET WHERE REPORT_ID=?) AND DELETED=? ORDER BY REPORT_DEF_ID asc NULLS LAST"",""i"":17,""t"":40,""slft"我们希望从中提取如 PLV=REQ, CMN="Dub Airport Corporation Limited", STK={"n":"..."} 等形式的键值对,并将其存储到Map<String, String>中。简单的字符串分割方法,如基于空格的split(),在这种情况下会失效,因为它无法正确处理包含空格的带引号值或嵌套结构。
立即学习“Java免费学习笔记(深入)”;
为了准确捕获不同类型的值,我们需要一个更为复杂的正则表达式。这个正则表达式需要能够识别:
以下是用于解决此问题的正则表达式:
(w+)=((?={)(?:(?=.*?{(?!.*?)(.*}(?!.*?).*))(?=.*?}(?!.*?)(.*)).)+?.*?(?=)[^{]*(?=$)|"{2}(.*?)"{2}|(S+))让我们逐步解析这个正则表达式的各个部分:
(w+):
=:
((?={)(?:(?=.*?{(?!.*?)(.*}(?!.*?).*))(?=.*?}(?!.*?)(.*)).)+?.*?(?=)[^{]*(?=$)|"{2}(.*?)"{2}|(S+)):
作用:这整个复杂的结构是为了捕获值(Value),它通过 |(或)运算符提供了三种不同的匹配模式,以适应不同类型的值。整个值被捕获到组2中。
模式一:处理嵌套的大括号结构(?={)(?:(?=.*?{(?!.*?)(.*}(?!.*?).*))(?=.*?}(?!.*?)(.*)).)+?.*?(?=)[^{]*(?=$)
模式二:处理双引号括起来的值|"{2}(.*?)"{2}
模式三:处理简单的非空白值|(S+)
在Java中,我们使用 java.util.regex.Pattern 和 java.util.regex.Matcher 类来执行正则表达式匹配。
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LogParser {
public static void main(String[] args) {
String logString = "DC696,"/xi/ajax/remoting/call/plaincall/adhocReportBuilderControllerProxy.getRortList.dwr","2222-11-10 08:32:22,351 PLV=REQ CIP=9.9.9.7 CMID=syairp CMN=""Dub Airport Corporation Limited"" SN=sfv4_APM180885. DPN=dbPool66HFT01 UID=3862D04108 UN=91F6025D47F01D IUID=1931 LOC=en_GB EID=""EVENT-UNKNOWN-UNKNOWN-ob55abe0118-201110083217-396080"" AGN=""[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/5537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35]"" RID=REQ-[7274545] MTD=POST URL=""/xi/ajax/remoting/call/plaincall/adhocRrtBuilderCoollerProxy.getRtList.dwr"" RQT=2835 MID=ADIN PID=ADMIN PQ=ADIN_PAGE SUB=0 MEM=2331036 CPU=2410 UCPU=2300 SCPU=110 FRE=10 FWR=0 NRE=2281 NWR=218 SQLC=43 SQLT=142 RPS=200 SID=60826A3FAB005A8A9B930177C5******.pc6bc1029 GID=e262dde6d0e040070b58afd4c8 HSID=ddc665538db779508d3213c0bb63bcb1c49fe8236d5f0884ae975915728e61 CSL=CRITICAL CCON=0 CSUP=0 CLOC=0 CEXT=0 CREM=0 STK={""n"":""/xi/ajax/remoting/call/plaincall/adhocReportBuilderControllerProxy.getrtList.dwr"",""i"":1,""t"":2835,""slft"":2679,""sub"":[{""n"":""SQL:select * from sfv4_HOUA180885.REPORT_DEF WHERE REPORT_DEF_ID IN (SELECT REPORT_DEF_ID FROM sfv4_HA80885.REPORT_DTASET WHERE REPORT_ID=?) AND DELETED=? ORDER BY REPORT_DEF_ID asc NULLS LAST"",""i"":17,""t"":40,""slft"":40,""st"":337,""m"":220958,""nr"":154,""rt"":0,""rn"":22,""fs"":0}]} ","2022-11-09T21:32:22.351+0000",p66cf1029,"dc606_ss_application",1,"/app/tomcat/logs/pef.log","perf_log_yxx",swsskix13";
// 注意:在Java字符串中,正则表达式中的双引号需要用反斜杠转义
// 并且为了表示字面量 ",在正则表达式中用 ",在Java字符串中用 \"
// 示例中的 `"{2}` 表示两个字面量 `"`,在Java字符串中写为 `\"{2}`
String regex = "(\w+)=((?=\{)(?:(?=.*?\{(?!.*?\3)(.*\}(?!.*\4).*))(?=.*?\}(?!.*\4)(.*)).)+?.*?(?=\3)[^{]*(?=\4$)|"{2}(.*?)"{2}|(\S+))";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(logString);
Map<String, String> result = new HashMap<>();
while (m.find()) {
String key = m.group(1); // 捕获组1是键
// 捕获组2是整个值,但我们需要根据是哪种类型的值来获取实际内容
String value = null;
if (m.group(5) != null) { // 如果是双引号包围的值(组5)
value = m.group(5);
} else if (m.group(6) != null) { // 如果是简单的非空白值(组6)
value = m.group(6);
} else { // 否则,是平衡大括号结构的值(组2的整体部分)
value = m.group(2);
}
// 对于STK这种JSON字符串,可能需要进一步处理内部的双引号转义,例如 `""` 替换为 `"`
if (key.equals("STK") && value != null) {
value = value.replace("""", """);
}
result.put(key, value);
System.out.println(key + " => " + value);
}
System.out.println("
--- Extracted Map ---");
result.forEach((k, v) -> System.out.println(k + "=" + v));
}
}代码解释:
通过本教程,我们学习了如何利用Java正则表达式从复杂的日志字符串中高效地提取KEY=VALUE对。掌握这种技术对于处理半结构化数据至关重要,它能帮助开发者将原始日志数据转换为可编程访问的结构化信息,从而进行进一步的分析、存储或展示。虽然正则表达式功能强大,但在实际应用中,仍需根据具体场景权衡其复杂性、性能和可维护性。
以上就是Java日志字符串中KEY=VALUE对的正则表达式提取教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号