
本文旨在提供一个java解决方案,利用强大的正则表达式从包含多种值类型(包括简单值、双引号字符串和嵌套json结构)的复杂日志字符串中准确提取出所有的key=value对,并将其存储到map中。文章详细解析了核心正则表达式的构成,并提供了完整的java代码实现及使用说明,帮助开发者高效处理非结构化日志数据。
在日常的系统维护和故障排查中,解析日志文件是必不可少的工作。然而,日志数据往往是非结构化的,尤其是当日志条目中包含大量以 KEY=VALUE 形式表示的配置或事件属性时,如何高效、准确地提取这些信息成为一个挑战。传统的字符串分割方法在遇到值中包含空格、引号或嵌套结构时,往往力不从心。本教程将展示如何利用Java的正则表达式功能,解决从复杂日志字符串中提取 KEY=VALUE 对的问题。
考虑以下日志字符串示例:
String s0 = "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"":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";其中,键(KEY)和值(VALUE)的格式多种多样:
由于值本身可能包含空格、等号,甚至嵌套的括号,简单的 String.split(" ") 无法正确识别键值对的边界。正则表达式则提供了强大的模式匹配能力,能够精确地定义和捕获这些复杂的结构。
立即学习“Java免费学习笔记(深入)”;
我们将使用以下正则表达式来匹配 KEY=VALUE 对:
(w+)=((?=\{)(?:(?=.*?\{(?!.*?\3)(.*\}(?!.*\4).*))(?=.*?\}(?!.*\4)(.*)).)+?.*?(?=\3)[^{]*(?=\4$)|"{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/555.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字符串中的反斜杠需要双重转义,所以 \{ 变为 \\{
// 原始正则表达式:(w+)=((?=\{)(?:(?=.*?\{(?!.*?\3)(.*\}(?!.*\4).*))(?=.*?\}(?!.*\4)(.*)).)+?.*?(?=\3)[^{]*(?=\4$)|"{2}(.*?)"{2}|(\S+))
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捕获组
String value;
// 根据哪个捕获组匹配到了值来确定最终的值
if (m.group(5) != null) { // 如果是双引号包裹的值
value = m.group(5);
} else if (m.group(6) != null) { // 如果是简单值
value = m.group(6);
} else { // 否则是嵌套花括号结构,其完整内容在第2捕获组
value = m.group(2);
}
result.put(key, value);
System.out.println(key + " => " + value);
System.out.println("----");
}
// 打印最终的Map
// System.out.println("
Extracted Map: " + result);
}
}代码说明:
运行上述Java代码,将得到以下键值对的输出:
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/555.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}]}
----通过本教程,我们展示了如何在Java中利用一个强大的正则表达式,从复杂的日志字符串中准确、高效地提取 KEY=VALUE 对。虽然正则表达式本身较为复杂,但其在处理特定模式匹配问题上的强大能力是毋庸置疑的。理解其工作原理并正确应用,将大大提高日志解析的效率和准确性。
以上就是Java中利用正则表达式从复杂日志字符串提取KEY=VALUE对的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号