Guava 拆分器到键值映射,字符串中包含拆分器字符
Guava Splitter to key value map with splitter character included in strings
我正在尝试使用 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 无法解析它。您能帮我如何更改模式以正确获取所有字段吗?
不确定 Guava 拆分器的工作原理,但如果您使用常规 Pattern
和 Matcher
类,您可以使用下面的正则表达式来捕获您的键和值:
([\w-]+?)=(".*?"|\S+)
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"`
我不确定答案是否可以用一个正则表达式来完成,但可以相对轻松地制定一个可行的解决方案:
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
使用正则表达式的问题在于拆分的内在目标只是找到分隔符。这与正常的正则表达式用法不同,在常规正则表达式用法中,您可以使用组来 select 您想要的东西;当你分裂时,你试图匹配你不想要的东西,这变得非常混乱。
Exception java.lang.IllegalArgumentException: Chunk [location="= /v1/tXXXX"] is not a valid entry
从您的代码中抛出,因为 keyValueSeparator
在块中出现不止一次。您可以调整 keyValueSeparator
以便仅匹配等号后跟您的值模式。例如:
final String keyPattern = "\S+";
final String valuePattern = "(\S+|\"[^\"]*\")";
parserMap = Splitter.onPattern("\s(?=" + keyPattern + "=" + valuePattern + ")")
.omitEmptyStrings()
.withKeyValueSeparator(Splitter.onPattern("=(?=" + valuePattern + ")"))
.split(line);
请注意,如果您的行中有类似 key="key=value"
的内容,这将不起作用。
在 withKeyValueSeparator
拆分器上使用 limit
Splitter.onPattern("\s(?=([^\\"]*\\"[^\\"]*\\")*[^\\"]*$)")
.omitEmptyStrings()
.withKeyValueSeparator(Splitter.on("=").limit(2).trimResults())
.split(line);
参见GitHub问题:https://github.com/google/guava/issues/1900
我正在尝试使用 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 无法解析它。您能帮我如何更改模式以正确获取所有字段吗?
不确定 Guava 拆分器的工作原理,但如果您使用常规 Pattern
和 Matcher
类,您可以使用下面的正则表达式来捕获您的键和值:
([\w-]+?)=(".*?"|\S+)
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"`
我不确定答案是否可以用一个正则表达式来完成,但可以相对轻松地制定一个可行的解决方案:
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
使用正则表达式的问题在于拆分的内在目标只是找到分隔符。这与正常的正则表达式用法不同,在常规正则表达式用法中,您可以使用组来 select 您想要的东西;当你分裂时,你试图匹配你不想要的东西,这变得非常混乱。
Exception java.lang.IllegalArgumentException: Chunk [location="= /v1/tXXXX"] is not a valid entry
从您的代码中抛出,因为 keyValueSeparator
在块中出现不止一次。您可以调整 keyValueSeparator
以便仅匹配等号后跟您的值模式。例如:
final String keyPattern = "\S+";
final String valuePattern = "(\S+|\"[^\"]*\")";
parserMap = Splitter.onPattern("\s(?=" + keyPattern + "=" + valuePattern + ")")
.omitEmptyStrings()
.withKeyValueSeparator(Splitter.onPattern("=(?=" + valuePattern + ")"))
.split(line);
请注意,如果您的行中有类似 key="key=value"
的内容,这将不起作用。
在 withKeyValueSeparator
拆分器上使用 limit
Splitter.onPattern("\s(?=([^\\"]*\\"[^\\"]*\\")*[^\\"]*$)")
.omitEmptyStrings()
.withKeyValueSeparator(Splitter.on("=").limit(2).trimResults())
.split(line);
参见GitHub问题:https://github.com/google/guava/issues/1900