Java正则表达式在多个分隔符上拆分,包括其他分隔符的子字符串

Java正则表达式在多个分隔符上拆分,包括其他分隔符的子字符串,java,regex,dictionary,split,Java,Regex,Dictionary,Split,我正在尝试使用正则表达式和已知分隔符将字符串转换为值映射。我拥有的代码可以工作,但是如果我使用的分隔符是另一个分隔符的子字符串,它就不会被解析(正确地) 让我们直接切入一些示例输入、错误输出、预期输出和代码 示例输入:“艺术家:foo bar fooo标题:bar fooo bar尺寸:x z y框架尺寸:y z x”(如您所见,有“尺寸”和“框架尺寸”) 输出错误:{Artist:=foo bar fooo,Title:=bar fooo bar,维度:=x z y,维度:=y z x}(框架

我正在尝试使用正则表达式和已知分隔符将字符串转换为值映射。我拥有的代码可以工作,但是如果我使用的分隔符是另一个分隔符的子字符串,它就不会被解析(正确地)

让我们直接切入一些示例输入、错误输出、预期输出和代码

示例输入:
“艺术家:foo bar fooo标题:bar fooo bar尺寸:x z y框架尺寸:y z x”
(如您所见,有“尺寸”和“框架尺寸”)

输出错误:
{Artist:=foo bar fooo,Title:=bar fooo bar,维度:=x z y,维度:=y z x}
(框架维度在维度下被捕获!)

预期输出:
Artist:=foo-bar-fooo,Title:=bar-fooo-bar,尺寸:=x-z-y,框架尺寸:=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;
}
String DELIMITER=“[Aa]rtist:|[Tt]itle:|[Ff]ramed[Dd]维度:|[Dd]维度:”
...
公共映射解析映射(字符串str){
Map itemMap=newlinkedhashmap();
String infos[]=str.split((?=“+分隔符+”);//在分隔符处拆分
用于(字符串信息:infos){
试一试{

String[]tmp=info.split((?而不是
split
操作将此正则表达式与两个捕获的组一起使用:

(?<key>[\w\s]+:)\s*(?<value>.+?)\s*(?=(?:[Aa]rtist|[Tt]itle|(?:[Ff]ramed )?[Dd]imensions):|$)
(?[\w\s]+:)\s*(?。+)\s*(?=(?:[Aa]rtist |[Tt]itle |)(?:[Ff]ramed)?[Dd]维度:|$)

代码:

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);
final String regex=“(?[\\w\\s]+:)\\s*(?。+?)\\s*(?=(?:[Aa]rtist|[Tt]itle |)(?:[Ff]ramed)?[Dd]维度):|$”;
final String=“艺术家:foo标题:条形尺寸:x框架尺寸:y”;
最终模式=Pattern.compile(regex);
最终匹配器m=模式匹配器(字符串);
Map itemMap=newlinkedhashmap();
while(m.find()){
itemMap.put(m.group(“key”)、m.group(“value”);
}
System.out.println(“itemMap:+itemMap”);

而不是
拆分
操作将此正则表达式与两个捕获的组一起使用:

(?<key>[\w\s]+:)\s*(?<value>.+?)\s*(?=(?:[Aa]rtist|[Tt]itle|(?:[Ff]ramed )?[Dd]imensions):|$)
(?[\w\s]+:)\s*(?。+)\s*(?=(?:[Aa]rtist |[Tt]itle |)(?:[Ff]ramed)?[Dd]维度:|$)

代码:

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);
final String regex=“(?[\\w\\s]+:)\\s*(?。+?)\\s*(?=(?:[Aa]rtist|[Tt]itle |)(?:[Ff]ramed)?[Dd]维度):|$”;
final String=“艺术家:foo标题:条形尺寸:x框架尺寸:y”;
最终模式=Pattern.compile(regex);
最终匹配器m=模式匹配器(字符串);
Map itemMap=newlinkedhashmap();
while(m.find()){
itemMap.put(m.group(“key”)、m.group(“value”);
}
System.out.println(“itemMap:+itemMap”);

您的正则表达式是一个非消耗性的正向前瞻,它测试字符串中的每个位置,因此,它可以匹配重叠的字符串

您可以使用匹配方法将分隔符捕获到组1中,然后捕获未启动任何分隔符的任何字符:

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;
}

这里,

  • ([Aa]rtist:|[Tt]itle:|[Ff]ramed[Dd]维度:|[Dd]维度:)
    -组1匹配任何分隔符
  • ((?:(?![Aa]rtist:|[Tt]itle:|[Ff]ramed[Dd]dimensions:|[Dd]dimensions:)*)
    -匹配除换行符(
    )以外的任何字符,不启动任何分隔符字符序列的0+次(
    *

您的正则表达式是一个非消耗性的正向前瞻,它测试字符串中的每个位置,因此,它可以匹配重叠的字符串

您可以使用匹配方法将分隔符捕获到组1中,然后捕获未启动任何分隔符的任何字符:

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;
}

这里,

  • ([Aa]rtist:|[Tt]itle:|[Ff]ramed[Dd]维度:|[Dd]维度:)
    -组1匹配任何分隔符
  • ((?:(?![Aa]rtist:|[Tt]itle:|[Ff]ramed[Dd]dimensions:|[Dd]dimensions:)*)
    -匹配除换行符(
    )以外的任何字符,不启动任何分隔符字符序列的0+次(
    *

如果预期输入始终采用以下格式
艺术家:foo标题:条形尺寸:x框架尺寸:y

i、 e,“D”在维度上始终是大写, 你可以用 字符串分隔符=“[Aa]rtist:|[Tt]itle:|[Ff]ramed[Dd]维度:|维度:”; 而不是
String DELIMITER=“[Aa]rtist:|[Tt]itle:|[Ff]ramed[Dd]维度:|[Dd]维度:”

如果预期输入始终采用以下格式
艺术家:foo标题:条形尺寸:x框架尺寸:y

i、 e,“D”在维度上始终是大写, 你可以用 字符串分隔符=“[Aa]rtist:|[Tt]itle:|[Ff]ramed[Dd]维度:|维度:”; 而不是
字符串分隔符=“[Aa]rtist:|[Tt]itle:|[Ff]框架[Dd]维度:|[Dd]维度:"

在预期中,它不应该是
Title:=bar
而不是
Title=bar
?你完全正确,谢谢你抓住了我的打字错误!请看@WiktorStribiżew,你的解决方案对我很有效。想回答这个问题,我会接受它吗?在预期中,它不应该是
Title:=bar
而不是
Title=bar
?你完全正确谢谢你抓住我的打字错误!请看@WiktorStribiżew,你的解决方案对我有效。想回答这个问题,我会接受吗?这只得到下面的单词。我需要每个单词直到下一个分隔符。这只得到下面的单词。我需要每个单词直到下一个分隔符。