我尝试使用正则表达式和已知的分隔符将字符串转换为值的映射。我的代码有效,但是如果我使用的分隔符是另一个分隔符的子字符串,则不会对其进行解析(正确)。
让我们直接切换到一些示例输入,错误输出,预期输出和代码!
示例输入:"Artist: foo bar foooo Title: bar fooo bar Dimensions: x z y Framed dimensions: y z x"
(正如您所看到的那样"尺寸"以及"框架尺寸")
错误输出:{Artist:=foo bar foooo, Title:=bar fooo bar, Dimensions:=x z y, dimensions:=y z x}
(框架尺寸在尺寸下被捕获!)
预期输出:Artist:=foo bar foooo, Title:=bar fooo bar, Dimensions:=x z y, Framed dimensions:=y z x}
代码示例:
String DELIMITER = "[Aa]rtist:|[Tt]itle:|[Ff]ramed [Dd]imensions:|[Dd]imensions:"
...
public Map<String, String> parseToMap(String str) {
Map<String, String> itemMap = new LinkedHashMap<>();
String infos[] = str.split("(?=" + DELIMITER + ')'); //split at delimiters
for(String info : infos) {
try {
String[] tmp = info.split("(?<=" + DELIMITER + ')'); //split to key/val pair
itemMap.put(tmp[0].trim(), tmp[1].trim());
} catch (IndexOutOfBoundsException e) {
//Skip if no key/val pair
}
}
return itemMap;
}
我也觉得这有点像个hackish。如果有一个更优雅的解决方案,我很高兴听到它。虽然如果我们现在可以让它工作,我总是可以去CodeReview旅行:)
修改 我需要从分隔符到分隔符的每个单词,而不仅仅是分隔符后面的单词。
答案 0 :(得分:3)
而不是split
操作使用此正则表达式与2个捕获的组:
(?<key>[\w\s]+:)\s*(?<value>.+?)\s*(?=(?:[Aa]rtist|[Tt]itle|(?:[Ff]ramed )?[Dd]imensions):|$)
<强>代码:强>
final String regex = "(?<key>[\\w\\s]+:)\\s*(?<value>.+?)\\s*(?=(?:[Aa]rtist|[Tt]itle|(?:[Ff]ramed )?[Dd]imensions):|$)";
final String string = "Artist: foo Title: bar Dimensions: x Framed dimensions: y";
final Pattern pattern = Pattern.compile(regex);
final Matcher m = pattern.matcher(string);
Map<String, String> itemMap = new LinkedHashMap<>();
while (m.find()) {
itemMap.put(m.group("key"), m.group("value"));
}
System.out.println("itemMap: " + itemMap);
答案 1 :(得分:2)
你的正则表达式是一个非消费性的正向前瞻,它测试字符串中的每个位置,因此,它可以匹配重叠的字符串。
您可以使用匹配方法将分隔符捕获到第1组,然后使用任何不启动任何分隔符的char:
public static Map<String, String> parseToMap(String str) {
String DESCRIPTION_DELIMITER = "[Aa]rtist:|[Tt]itle:|[Ff]ramed [Dd]imensions:|[Dd]imensions:";
Map<String, String> itemMap = new LinkedHashMap<>();
Pattern p = Pattern.compile("(" + DESCRIPTION_DELIMITER + ")((?:(?!" + DESCRIPTION_DELIMITER + ").)*)"); //split to key/val pair
Matcher m = p.matcher(str);
while(m.find()) {
itemMap.put(m.group(1).trim(), m.group(2).trim());
}
return itemMap;
}
请参阅Java demo。
正则表达式看起来像
([Aa]rtist:|[Tt]itle:|[Ff]ramed [Dd]imensions:|[Dd]imensions:)((?:(?![Aa]rtist:|[Tt]itle:|[Ff]ramed [Dd]imensions:|[Dd]imensions:).)*)
请参阅online demo。
下面,
([Aa]rtist:|[Tt]itle:|[Ff]ramed [Dd]imensions:|[Dd]imensions:)
- 与任何分隔符匹配的第1组((?:(?![Aa]rtist:|[Tt]itle:|[Ff]ramed [Dd]imensions:|[Dd]imensions:).)*)
- tempered greedy token匹配除换行符(.
)以外的任何字符,0 +出现次数(*
),但不启动任何字符串分隔符字符序列。答案 2 :(得分:0)
如果输入预期始终采用以下格式
艺术家:foo标题:bar尺寸:x框架尺寸:y
,即“D”总是在Dimensions中, 您可以使用 String DELIMITER =“[Aa] rtist:| [Tt] itle:| [Ff] ramed [Dd] imensions:| Dimensions:”; 代替 String DELIMITER =“[Aa] rtist:| [Tt] itle:| [Ff] ramed [Dd] imensions:| [Dd] imensions:”