我正在尝试使用Guava拆分器解析日志文件。日志文件如下所示:
appName=XXX clientIp=X.X.X timestamp="2017-06-05T13:22:12-07:00" request="POST /forward HTTP/1.1" statusCode=204 bytesOut=1167 totalTime=0.062 bytesIn=1289 sourceHost=XXXX connId=49936598 connReqs=9 upInstance=XXX:104:XXX-XXX:8664:17F34 upConnectSec=0.052 upAddr="XX.XX.XX:123" upHost="vcv08it-cvcv2801:8464" upHdrTimeSec=0.058 upRespTimeSec=0.058 pid=32561 upStatusCode=204 message="Access Log" corrKey=GMIFCDIKRZR2T4VZQXJA2IT6 upCached=- length=0 partition=XXX location="= /v1/tXXXX" xff="XX.XX.XX.XX" referer="-" user-agent="Apache-HttpAsyncClient/4.1.1 (Java/1.8.0_131)\" rateLimitCurrentValues="--" rateLimitTimeMs=\"-:-"
我用这段代码来解析它:
Map<String, String> parserMap;
parserMap = Splitter.onPattern("\\s(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)")
.omitEmptyStrings()
.withKeyValueSeparator(Splitter.onPattern("="))
.split(line);
我的问题是location =“= / v1 / tXXXX”字段,字符串中有'=',当前withKeyValueSeperator无法解析它。你能帮我解决一下如何更改模式以正确获取所有字段吗?
答案 0 :(得分:1)
不确定Guava分割器的工作原理,但如果您使用常规的Pattern
和Matcher
类,则可以使用以下正则表达式来捕获您的键和值:
([\w-]+?)=(".*?"|\S+)
<强> Regex demo 强>
Java代码
String text = "your string";
Pattern pattern = Pattern.compile("([\\w-]+?)=(\".*?\"|\\S+)");
Matcher m = pattern.matcher(text);
Map<String, String> parserMap = new HashMap<>();
while (m.find()) {
String key = m.group(1);
String value = m.group(2);
parserMap.put(key, value);
}
在这里准备了一个IdeOne java工作演示:
您可以在下面看到匹配信息的样本
Match 1
Group 1. 0-7 `appName`
Group 2. 8-11 `XXX`
Match 2
Group 1. 12-20 `clientIp`
Group 2. 21-26 `X.X.X`
Match 3
Group 1. 27-36 `timestamp`
Group 2. 37-64 `"2017-06-05T13:22:12-07:00"`
Match 4
Group 1. 65-72 `request`
Group 2. 73-97 `"POST /forward HTTP/1.1"`
答案 1 :(得分:0)
我不确定单个正则表达式可以解决问题,但可以相对轻松地制作出可行的解决方案:
parserMap = Splitter.onPattern("\\s(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)")
.omitEmptyStrings()
.splitToList(line)
.stream()
.collect(Collectors.toMap(
s -> s.split("=", 2)[0], // the first part of split gets the key
s -> s.split("=", 2)[1] // everything else is the value
)
);
尝试对split
使用正则表达式的麻烦在于,split的固有目标只是找到分隔符。这与正常的正则表达式使用不同,您可以使用组来选择所需的内容;当你分手时,你正试图匹配你不想要的东西,这真的很混乱。
答案 2 :(得分:0)
从代码中抛出异常java.lang.IllegalArgumentException: Chunk [location="= /v1/tXXXX"] is not a valid entry
,因为keyValueSeparator
在块中不止一次出现。您可以调整keyValueSeparator
,以便只匹配您的值模式后面的等号。 e.g:
final String keyPattern = "\\S+";
final String valuePattern = "(\\S+|\"[^\"]*\")";
parserMap = Splitter.onPattern("\\s(?=" + keyPattern + "=" + valuePattern + ")")
.omitEmptyStrings()
.withKeyValueSeparator(Splitter.onPattern("=(?=" + valuePattern + ")"))
.split(line);
请注意,如果您的行中有key="key=value"
之类的内容,则无法使用此功能。
答案 3 :(得分:0)
在limit
拆分器上使用withKeyValueSeparator
Splitter.onPattern("\\s(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)")
.omitEmptyStrings()
.withKeyValueSeparator(Splitter.on("=").limit(2).trimResults())
.split(line);
请参阅GitHub问题:https://github.com/google/guava/issues/1900