Java 如何使用Splitter.MapSplitter从Guava拆分字符串直到指定键?

Java 如何使用Splitter.MapSplitter从Guava拆分字符串直到指定键?,java,guava,Java,Guava,我有一个字符串,如“key1:value1 | prop:id | key3:value3 | id:ABC.CDE | key4:value4”,如何使用直到id键进行拆分 Splitter.mapslitter.on(“|”).withKeyValuePairs(“:”).split()返回一个不可修改的映射,因此我需要遍历映射直到id键,并在这种情况下将条目放入一个新映射。这看起来不是一个有效的解决方案 String.substring(0,String.indexOf('|',Stri

我有一个字符串,如
“key1:value1 | prop:id | key3:value3 | id:ABC.CDE | key4:value4”
,如何使用直到id键进行拆分

  • Splitter.mapslitter.on(“|”).withKeyValuePairs(“:”).split()
    返回一个不可修改的映射,因此我需要遍历映射直到id键,并在这种情况下将条目放入一个新映射。这看起来不是一个有效的解决方案
  • String.substring(0,String.indexOf('|',String.indexOf(“id”))
    不是选项,因为“id”字符串可以是id键之前任何值的子字符串
  • 或者我可以使用两个拆分器,EntrySpliter将字符串拆分为条目,keyValueSplitter将条目拆分为键值对,然后在未到达特定键时将其放入映射

最好的解决方案是什么?

除了将MapSplitter的输出复制到另一个映射并对其进行操作(假设保留了键顺序)之外,我看不到其他解决方案,只能自己部分解析

您关于可能出现在别处的“id”的评论是正确的,因此您需要搜索更具体的内容,如
id:…
id:…
,如果
id
是第一个键

private static final Pattern ID_REGEX = Pattern.compile("(^|\\|)id:.+?\\|");
...
Matcher matcher = ID_REGEX.matcher(line);
if (matcher.find()) {
    lineForMapSplitter = line.substring(0, matcher.end()-1);
}

除了将MapSplitter的输出复制到另一个映射并对其进行操作(假设保留了键顺序),我看不到其他解决方案,只有自己进行部分解析

您关于可能出现在别处的“id”的评论是正确的,因此您需要搜索更具体的内容,如
id:…
id:…
,如果
id
是第一个键

private static final Pattern ID_REGEX = Pattern.compile("(^|\\|)id:.+?\\|");
...
Matcher matcher = ID_REGEX.matcher(line);
if (matcher.find()) {
    lineForMapSplitter = line.substring(0, matcher.end()-1);
}

首先,不要直接使用
Splitter.mapslitter
,而是使用
Splitter#withKeyValueSeparator
(此处:
Splitter.on(“|”).withKeyValueSeparator(“:”)
。其次,在您的情况下,最有效的方法是手动拆分对,然后在谓词(关于key==id)的情况下拆分对不满足,直到最后才创建地图

TIMTOWDI,但我正在使用,它为您的用例提供了有用的方法。
Seq.Seq(Iterable)
是创建流的简单助手,更重要的是,它将拾取所有值,直到找到
id
键:

private static final Splitter PAIRS_SPLITTER = Splitter.on('|');
private static final Splitter KEY_VALUE_SPLITTER = Splitter.on(':');
private static final String INVALID_ENTRY_MESSAGE = "Chunk [%s] is not a valid entry";

private Map<String, String> homebrewMapSplitter(final String string)
{
    return Seq.seq(PAIRS_SPLITTER.split(string))
            .map(this::createEntry)
            .limitUntilClosed(e -> e.getKey().equals("id"))
            .collect(ImmutableMap.toImmutableMap(
                    Map.Entry::getKey,
                    Map.Entry::getValue)
            );
}

// ~copied from MapSplitter#split(CharSequence)
private Map.Entry<String, String> createEntry(final String entry)
{
    Iterator<String> entryFields = KEY_VALUE_SPLITTER.split(entry).iterator();
    checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
    String key = entryFields.next();

    checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
    String value = entryFields.next();

    checkArgument(!entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);

    return Maps.immutableEntry(key, value);
}
private static final Splitter PAIRS_Splitter=Splitter.on(“|”);
私有静态最终拆分器KEY_VALUE_Splitter=Splitter.on(':');
私有静态最终字符串无效\u条目\u MESSAGE=“Chunk[%s]不是有效条目”;
私有映射homebrewMapSplitter(最终字符串)
{
返回顺序顺序(成对拆分器拆分(字符串))
.map(此::createEntry)
.limituntlclosed(e->e.getKey().equals(“id”))
.collect(ImmutableMap.toImmutableMap)(
Map.Entry::getKey,
Map.Entry::getValue)
);
}
//~从MapSplitter复制#split(CharSequence)
私有映射项createEntry(最终字符串项)
{
Iterator entryFields=KEY_VALUE_SPLITTER.split(entry.Iterator();
checkArgument(entryFields.hasNext(),无效的\u条目\u消息,条目);
String key=entryFields.next();
checkArgument(entryFields.hasNext(),无效的\u条目\u消息,条目);
字符串值=entryFields.next();
checkArgument(!entryFields.hasNext(),无效的\u条目\u消息,条目);
返回Maps.immutableEntry(键、值);
}

首先,不要直接使用
Splitter.mapslitter
,而是使用
Splitter#withKeyValueSeparator
(此处:
Splitter.on('.')。withKeyValueSeparator(':'))
。其次,在您的情况下,最有效的方法是手动拆分对,然后在谓词(关于key==id)的情况下拆分对不满足,直到最后才创建地图

TIMTOWDI,但我正在使用,它为您的用例提供了有用的方法。
Seq.Seq(Iterable)
是创建流的简单助手,更重要的是,它将拾取所有值,直到找到
id
键:

private static final Splitter PAIRS_SPLITTER = Splitter.on('|');
private static final Splitter KEY_VALUE_SPLITTER = Splitter.on(':');
private static final String INVALID_ENTRY_MESSAGE = "Chunk [%s] is not a valid entry";

private Map<String, String> homebrewMapSplitter(final String string)
{
    return Seq.seq(PAIRS_SPLITTER.split(string))
            .map(this::createEntry)
            .limitUntilClosed(e -> e.getKey().equals("id"))
            .collect(ImmutableMap.toImmutableMap(
                    Map.Entry::getKey,
                    Map.Entry::getValue)
            );
}

// ~copied from MapSplitter#split(CharSequence)
private Map.Entry<String, String> createEntry(final String entry)
{
    Iterator<String> entryFields = KEY_VALUE_SPLITTER.split(entry).iterator();
    checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
    String key = entryFields.next();

    checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
    String value = entryFields.next();

    checkArgument(!entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);

    return Maps.immutableEntry(key, value);
}
private static final Splitter PAIRS_Splitter=Splitter.on(“|”);
私有静态最终拆分器KEY_VALUE_Splitter=Splitter.on(':');
私有静态最终字符串无效\u条目\u MESSAGE=“Chunk[%s]不是有效条目”;
私有映射homebrewMapSplitter(最终字符串)
{
返回顺序顺序(成对拆分器拆分(字符串))
.map(此::createEntry)
.limituntlclosed(e->e.getKey().equals(“id”))
.collect(ImmutableMap.toImmutableMap)(
Map.Entry::getKey,
Map.Entry::getValue)
);
}
//~从MapSplitter复制#split(CharSequence)
私有映射项createEntry(最终字符串项)
{
Iterator entryFields=KEY_VALUE_SPLITTER.split(entry.Iterator();
checkArgument(entryFields.hasNext(),无效的\u条目\u消息,条目);
String key=entryFields.next();
checkArgument(entryFields.hasNext(),无效的\u条目\u消息,条目);
字符串值=entryFields.next();
checkArgument(!entryFields.hasNext(),无效的\u条目\u消息,条目);
返回Maps.immutableEntry(键、值);
}

你说的“直到id键”是什么意思?你的意思是想在“id”之前保留所有键值对,并放弃其余的键值对吗?是的。我想用最有效的方法从上面的字符串获得以下映射:key1到value1,prop到id,key3到value3,id到ABC。cde你说的“直到id键”是什么意思“?您的意思是想保留“id”之前的所有键值对,并放弃其余的键值对吗?是的。我想以最有效的方式从上面的字符串获得以下映射:key1到value1,prop到id,key3到value3,id到ABC.CDE。”