![](/img/trans.png)
[英]Java: how to extract and populate values to a Map from a String based on a provided pattern?
[英]Creating a Map from a string based on the provided Keys when the string doesn't have delimiters in Java 8
给定以下String
:
String s = "DIMENSION 24cm 34cm 12cm DETAILED SPECIFICATION Twin/Twin XL Flat Sheet: 105"l x 74"w. CARE For best results, machine wash warm with like colors. COLOURS red blue green";
关键是 = DIMENSIONS, DETAILED SPECIFICATION, CARE, COLOURS
我们需要创建Map<String,String>
,其中键将如上所示,相应的文本将是值。
地图的内容将如下所示:
DIMENSION: 24cm 34cm 12cm,
DETAILED SPECIFICATION: Twin/Twin XL Flat Sheet: 105"l x 74"w,
CARE: For best results, machine wash warm with like colors,
COLOURS: red blue green
并且没有必要所有这些键和值都存在于字符串中。
假设输入String
中不存在键CARE
:
String s = "DIMENSION 24cm 34cm 12cm DETAILED SPECIFICATION Twin/Twin XL Flat Sheet: 105"l x 74"w. COLOURS red blue green";
地图的内容将如下所示:
DIMENSION: 24cm 34cm 12cm,
DETAILED SPECIFICATION: Twin/Twin XL Flat Sheet: 105"l x 74"w,
COLOURS: red blue green
即,如果给定字符串中不存在键,则相应的值也将不存在。 例如, DIMENSION
键不存在,字符串以"DETAILED SPECIFICATION ... "
开头。
由于字符串没有分隔符,我无法从中创建地图。
使用平面 Java,我可以这样做:
if(s.contains("ASSEMBLY")) {
ass = s.substring(s.indexOf("COLOURS") + 8);
s = s.replaceAll(s.substring(s.indexOf("COLOURS")),"");
}
if(s.contains("OVERALL")){
ov = s.substring(s.indexOf("CARE") + 5);
s = s.replaceAll(s.substring(s.indexOf("CARE")),"");
}
if(s.contains("CARE")){
care1 = s.substring(s.indexOf("DETAILED SPECIFICATION") + 24);
s = s.replaceAll(s.substring(s.indexOf("DETAILED SPECIFICATION")),"");
}
if(s.contains("DIMENSIONS")){
de1 = s.substring(s.indexOf("DIMENSIONS") + 11);
s =s.replaceAll(s.substring(s.indexOf("DIMENSIONS")),"");
}
如果我们有分隔符,那么我可以这样做。
Map<String, String> map = Stream.of(s)
.map(s -> s.split("="))
.collect(Collectors.toMap(s -> s[0], s -> s[1]));
正则表达式方法:
String s = "DIMENSION 24cm 34cm 12cm DETAILED SPECIFICATION Twin/Twin XL Flat Sheet: 105 w. COLOURS red blue green";
String[] keys = new String[]{"DIMENSION", "DETAILED SPECIFICATION", "CARE", "COLOURS"};
String keyRegex = String.join("|", keys);
Pattern p = Pattern.compile("(?<key>" + keyRegex + ") (?<value>((?!(" + keyRegex + ")).)*)");
Matcher m = p.matcher(s);
Map<String, String> result = new HashMap<>();
while (m.find()) {
result.put(m.group("key"), m.group("value"));
}
您可以从给定的键生成正则表达式并将其编译为模式。
我使用lookahead和lookbehind解决了这个问题:
public static Pattern getPattern(Collection<String> keys) {
String joinedKeys = String.join("|", keys);
String regex = String.format("(?<=%s)|(?=%s)", joinedKeys, joinedKeys); // creates a regex "(?<=DIMENSION|DETAILED\\sSPECIFICATION|CARE|COLOURS)|(?=DIMENSION|DETAILED\\sSPECIFICATION|CARE|COLOURS)"
return Pattern.compile(regex);
}
(?=foo)
- Lookahead - 匹配紧跟在foo
之后的位置;(?<=foo)
- Lookbehind - 匹配紧接在foo
之前的位置。有关更多信息,请查看本教程
当我们有一个模式时,我们可以使用Pattern.splitAsStream()
生成一个流。
public static Map<String, String> toMap(String source, Set<String> keys) {
return getPattern(keys).splitAsStream(source)
.collect(combineByKey(keys));
}
这个流的每个元素要么是键要么是值,为了获得流执行结果的映射,我们需要一个能够区分键和值的收集器。
我们可以使用Collector.of()
创建这样的收集器。 作为一个可变容器,我将使用map-entries的Deque
。
可以在下面的累加器函数中观察到的将空字符串用作键的情况表示当线程获取从值而不是键开始的数据时并行执行流时可能发生的情况,换句话说,一个键和一个值在不同的容器中。 当我们在组合器函数中合并容器时,这个问题得到了解决。
StringBuilder
用作值的中间类型,由Map.entry()
返回的条目是不可变的。
注意: Map.entry()
是在 Java 9 中引入的。要使此解决方案与Java 8兼容,请改用new AbstractMap.SimpleEntry<>()
(请参阅 JDK 8 的代码)。
public static Collector<String, ?, Map<String, String>> combineByKey(Set<String> keys) {
return Collector.of(
ArrayDeque::new,
(Deque<Map.Entry<String, StringBuilder>> deque, String next) -> {
if (keys.contains(next)) deque.add(Map.entry(next, new StringBuilder()));
else {
if (deque.isEmpty()) deque.add(Map.entry("", new StringBuilder(next)));
else deque.getLast().getValue().append(next);
}
},
(left, right) -> {
if (!right.isEmpty() && !left.isEmpty() && right.getFirst().getKey().isEmpty()) {
left.getLast().getValue().append(right.pollFirst().getValue());
}
left.addAll(right);
return left;
},
deque -> deque.stream().collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().toString().strip()
))
);
}
main()
public static void main(String[] args) {
String source = "DIMENSION 24cm 34cm 12cm DETAILED SPECIFICATION Twin/Twin XL Flat Sheet: 105l x 74w. CARE For best results, machine wash warm with like colors. COLOURS red blue green";
Set<String> keys = Set.of("DIMENSION", "DETAILED SPECIFICATION", "CARE", "COLOURS");
Map<String, String> result = toMap(source, keys); // converting the source string to map
result.forEach((k, v) -> System.out.println(k + " -> " + v)); // printing the result
}
输出:
COLOURS -> red blue green
DIMENSION -> 24cm 34cm 12cm
DETAILED SPECIFICATION -> Twin/Twin XL Flat Sheet: 105l x 74w.
CARE -> For best results, machine wash warm with like colors.
这可能会帮助您:
String str = "DIMENSION 24cm 34cm 12cm DETAILED SPECIFICATION Twin/Twin XL Flat Sheet: 105 w. CARE For best results, machine wash warm with like colors. COLOURS red blue green";
String[] keys = {"DIMENSIONS", "DETAILED SPECIFICATION", "CARE", "COLOURS"};
Map<String, String> map = new LinkedHashMap<>();
for (int index = 0; index < keys.length; index++) {
String subString = "";
if(index + 1 < keys.length) {
int start = str.indexOf(keys[index] + " ") > 0 ? str.indexOf(keys[index] + " ") + keys[index].length() : str.indexOf(keys[index]);
int end = str.indexOf(keys[index + 1]);
if(start < 0 || end < 0) {
continue;
}
subString = str.substring(start, end);
} else {
subString = str.substring(str.indexOf(keys[index] + " "));
}
map.put(keys[index], subString);
}
System.out.println(map);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.