[英]Java8: Looking for a better way of parsing a text of “key: value” lines
我有一串文字行。
一些行的格式为“key:value”。 其他人应该被忽视。
我有一个固定的(预定义的)键列表,我需要为HashMap提取值并放入HashMap。
所以,我正在做这样的事情:
BufferedReader reader = new BufferedReader(new StringReader(memoText));
reader.lines().forEach(line->{
if(line.startsWith("prefix1")){
// Some code is required here to get the value1
}
else if(line.startsWith("prefix2")){
// Some code is required here to get the value2
}
...
}
有没有更好的方法在Java 8中实现解析?
根据你当前的问题陈述。 您可以尝试下面的代码..
您可能希望根据需要进行更改:
import static java.util.stream.Collectors.toMap;
//skipped
Pattern pattern = Pattern.compile("([a-zA-Z]+)\\s*:\\s*(.*)");
try (Stream<String> stream = Files.lines(Paths.get("<PATH_TO_FILE>"))) {
Map<String, String> results =
stream.map(pattern::matcher)
.filter(Matcher::find)
.collect(toMap(a -> a.group(1), a -> a.group(2)));
}
让我知道,如果这不是你想要的
// define your fixed keys in a list
List<String> keys = Arrays.asList("key1", "key2");
reader.lines()
// use filter instead of if-else
.filter(line -> line.indexOf(":")>-1 && keys.contains(line.substring(0, line.indexOf(":"))))
// collect in to a map
.collect(Collectos.toMap(line -> {
return line.substring(0, line.indexOf(":"));
}, line -> {
return line.substring(line.indexOf(":") + 1);
}))
但是你必须确保每一行都有不同的密钥。 或者它将抛出java.lang.IllegalStateException: Duplicate key
你当然可以使用split
来做到这一点,但对于这样的情况,我认为正则表达式更灵活。 另请注意,按照您的示例,这是从字符串解析,因此我省略了对BufferedReader
异常处理和关闭。
这是一个Java 8版本:
static String memoText = "foo: fooValue\r\n" +
"otherKey: otherValue\r\n" +
"# something else like a comment line\r\n" +
"bar: barValue\r\n";
static Map<String, String> parseKeysValues(String memoText) {
Pattern pattern = Pattern.compile("([a-zA-Z]+)\\s*:\\s*(.*)");
Set<String> allowedKeys = new HashSet<>(Arrays.asList("foo", "bar"));
return new BufferedReader(new StringReader(memoText)).lines()
.map(pattern::matcher)
.filter(Matcher::matches)
.filter(m -> allowedKeys.contains(m.group(1)))
.collect(Collectors.toMap(m -> m.group(1), m -> m.group(2)));
}
这个想法是,给定一个行流,将它们与包含键和值的组的模式匹配。 当然,你可以调整模式以匹配任何有效字符或键和值,修剪空格等。然后, filter(Matcher::matches)
只允许成功匹配。 此时,正则表达式组1是键,组2是值,因此我们只能过滤允许的键,然后将结果放入Map中。
如果存在重复键,则会抛出异常。 要实现不同的策略,请将第三个参数添加到toMap
,以将新值与现有值合并。 例如,使用(a, b) -> b
来实现last-one-wins策略。
在Java 9中,这将变得更简单:
static Map<String, String> parseKeysValues9(String memoText) {
Set<String> allowedKeys = Set.of("foo", "bar");
return new Scanner(memoText).findAll("(?m)^([a-zA-Z]+)\\s*:\\s*(.*)$")
.filter(mr -> allowedKeys.contains(mr.group(1)))
.collect(Collectors.toMap(mr -> mr.group(1), mr -> mr.group(2), (a, b) -> b));
}
在这里,我们使用新的Set.of
静态工厂方法初始化允许的键集。 我们还使用Scanner
而不是BufferedReader
来解析输入。 新的findAll
方法将生成一个MatchResult
流,其中包含来自输入的所有匹配项。 一个小皱纹是我们必须修改模式来处理行结尾,因为我们不再逐行阅读。 默认情况下, ^
和$
匹配整个输入的开头和结尾。 我们插入(?m)
指令以启用MULTILINE
模式,以便^
和$
匹配行的开头和结尾。 最后,和以前一样,我们按允许的键过滤,然后收集到Map。 此示例将最后一次合并函数显示为toMap
的第三个参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.