2017-05-08 3 views
1

J'ai une chaîne comme "key1:value1|prop:id|key3:value3|id:ABC.CDE|key4:value4", comment puis-je diviser en utilisant Splitter.MapSplitter from Guava jusqu'à la clé d'identification?Comment séparer une chaîne en utilisant Splitter.MapSplitter de Guava jusqu'à une clé spécifique?

  • Splitter.MapSplitter.on('|').withKeyValuePairs(':").split() retourne une carte non modifiable, donc je dois marcher à travers la carte jusqu'à ce que la clé d'identification et mettre les entrées dans une nouvelle carte dans ce cas. Cela ne semble pas une solution efficace.
  • String.substring(0, String.indexOf('|', String.indexOf("id"))) n'est pas une option car la chaîne "id" peut être une sous-chaîne de toute valeur avant la clé id.
  • Ou je peux utiliser deux splitter, entrySplitter pour diviser la chaîne en entrées et keyValueSplitter pour diviser les entrées en paires clé-valeur, puis les mettre dans une carte tant que la clé spécifique n'a pas été atteinte.

Quelle est la meilleure solution?

+0

Que voulez-vous dire par "jusqu'à ce que la clé"? Voulez-vous dire que vous voulez conserver toutes les paires clé-valeur avant "id" et jeter le reste? –

+0

Oui. Je veux obtenir le mappage suivant de String au-dessus de la manière la plus efficace: key1 à value1 et prop à id et key3 à value3 et id à ABC.CDE – AggregateException

Répondre

0

En plus de copier la sortie de MapSplitter vers une autre carte et de la manipuler (en supposant que l'ordre des clés soit préservé), je ne vois pas d'autre solution que de vous analyser partiellement.

Votre remarque sur « id » peut apparaître ailleurs est correcte, vous devez rechercher quelque chose de plus spécifique, comme |id:...| ou id:...| si id est la première clé.

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

Tout d'abord, ne pas utiliser directement Splitter.MapSplitter, mais plutôt Splitter#withKeyValueSeparator (ici: Splitter.on('|').withKeyValueSeparator(':') En second lieu, dans votre cas paires la façon la plus efficace serait manuellement divisé et ensuite les paires séparées si votre prédicat (sur clé. == id) n'est pas remplie, et ne pas créer carte jusqu'à la fin.

TIMTOWDI, mais je l'utilise jOOL, qui a des méthodes utiles pour votre cas d'utilisation. Seq.seq(Iterable) est une aide simple pour créer des cours d'eau et, ce qui est plus important, Seq#limitUntilClosed(Predicate) va ramasser toutes les valeurs jusqu'à ce qu'il trouve id clé:

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