你當然可以使用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
來實施最後一個贏取策略。
在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
模式,以便^
和$
分別匹配行的開始和結束。最後,像以前一樣,我們按允許的鍵過濾,然後收集到一個地圖。此示例顯示了最後一次獲勝合併函數作爲toMap
的第三個參數。
我強烈推薦https://github.com/jOOQ/jool它大大增強了流,使它們與LINQ一樣簡單。即使你不使用它,只要瀏覽可用的函數,就可以知道你可以用流做什麼。 – Novaterata