如何使用Guava中的Splitter.MapSplitter将String拆分为特定键?

时间:2017-05-08 10:32:33

标签: java guava

我有一个像"key1:value1|prop:id|key3:value3|id:ABC.CDE|key4:value4"这样的字符串,如何使用Splitter.MapSplitter from Guava分割到id键?

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

什么是最佳解决方案?

2 个答案:

答案 0 :(得分:0)

除了将MapSplitter的输出复制到另一个Map并操纵它(假设键顺序被保留)之外,我认为除了部分解析你之外没有其他解决方案。

您对可能出现在其他地方的“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);
}

答案 1 :(得分:0)

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

TIMTOWDI,但我正在使用jOOL,它为您的用例提供了有用的方法。 Seq.seq(Iterable)是创建流的简单助手,更重要的是,Seq#limitUntilClosed(Predicate)会在找到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);
}