[英]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.