繁体   English   中英

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

[英]Java regex split on multiple delimiters including substrings of other delimiters

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

让我们直接切入一些样本输入,错误输出,预期输出和代码!

输入示例: "Artist: foo bar foooo Title: bar fooo bar Dimensions: xzy Framed dimensions: yzx" (您可以看到有“ Dimensions”和“ Framed Dimensions”)

错误输出: {Artist:=foo bar foooo, Title:=bar fooo bar, Dimensions:=xzy, dimensions:=yzx} (框架尺寸被尺寸吸引!)

预期输出: Artist:=foo bar foooo, Title:=bar fooo bar, Dimensions:=xzy, Framed dimensions:=yzx}

代码示例:

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

我也觉得这有点骇人听闻。 如果有更好的解决方案,我很高兴听到。 尽管如果我们现在就可以使它正常运行,我总是可以去CodeReview看看:)

编辑:我需要从定界符到定界符的每个单词,而不仅仅是定界符之后的单词。

而不是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中,然后将任何不启动任何定界符的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演示

正则表达式看起来像

([Aa]rtist:|[Tt]itle:|[Ff]ramed [Dd]imensions:|[Dd]imensions:)((?:(?![Aa]rtist:|[Tt]itle:|[Ff]ramed [Dd]imensions:|[Dd]imensions:).)*)

请参阅在线演示

这里,

  • ([Aa]rtist:|[Tt]itle:|[Ff]ramed [Dd]imensions:|[Dd]imensions:) -与任何定界符匹配的第1组
  • ((?:(?![Aa]rtist:|[Tt]itle:|[Ff]ramed [Dd]imensions:|[Dd]imensions:).)*) -与除a以外的任何char匹配的钢化贪婪令牌换行符char( . ),出现0+次( * ),不会开始任何分隔符字符序列。

如果期望输入始终为以下格式
艺术家:foo标题:bar尺寸:x框架尺寸:y

即,“ D”始终是维度中的大写字母,您可以使用String DELIMITER =“ [Aa] rtist:| [Tt] itle:| [Ff] ramed [Dd] imensions:| Dimensions:”; 而不是字符串DELIMITER =“ [Aa] rtist:| [Tt] itle:| [Ff] ramed [Dd] imensions:| [Dd] imensions:”

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM