2017-09-21 3 views
0

J'ai une chaîne qui vient en format particulier, donc je veux analyser cette chaîne dans la carte. J'ai une méthode ci-dessous qui analyse String à une carte et cela fonctionne bien.Parser une chaîne formatée dans une carte qui a la même clé plusieurs fois?

public static Map<String, String> parseStringToMap(String payload) { 
    try { 
     return Maps.newHashMap(Splitter.on("|").withKeyValueSeparator("=").split(payload)); 
    } catch (Exception ex) { 
     return ImmutableMap.of(); 
    } 
    } 

exemple de l'échantillon d'une chaîne:

"type=3|Id=23456|user=13456" 

Maintenant, parfois, quand j'ai même clé deux fois avec la même valeur dans la même chaîne payload, alors ma méthode ci-dessus échoue et il émet une exception. Par exemple pour la chaîne ci-dessous, cela ne fonctionne pas et échoue, puis retourne la carte vide car elle a deux fois la touche type. Que puis-je faire pour résoudre ce problème au lieu de réparer la charge utile de la chaîne?

"type=3|Id=23456|user=13456|type=3" 
Alors disons que si la même touche vient plusieurs fois, remplacez cette valeur de clé dans la carte au lieu d'échouer. Et je veux retourner une carte Mutable.

Je travaille toujours avec Java 7. Quelle est la meilleure et efficace façon de le faire?

+0

Êtes-vous capable d'utiliser Java 8? Si tel est le cas, vous pouvez utiliser un collecteur de regroupement pour créer une > ', ou similaire. –

+0

@AndyTurner Malheureusement, je suis toujours sur Java 7 et je ne peux pas encore utiliser Java 8. – user1950349

Répondre

1

Je ne sais pas d'une façon de le faire dans goyave, mais il est pas trop difficile à faire avec vieux Java simple:

Map<String, String> map = new HashMap<>(); 
for (String part : payload.split("\\|")) { 
    String[] subparts = part.split("=", 2); 
    map.put(subparts[0], subparts[1]); 
} 
return map; 

Si vous voulez simplement vérifier que la chaîne est dans le droit le format (autrement dit, il y a des éléments séparés tuyaux, contenant chacun un signe =), alors vous pouvez simplement utiliser indexOf pour trouver ces:

int start = 0; 
while (start < payload.length()) { 
    int end = payload.indexOf('|', start); 
    if (end == -1) { 
    end = payload.length(); 
    } 

    int equalsPos = payload.indexOf('=', start); 
    if (equalsPos > end || equalsPos < 0) { 
    // No = found between adjacent |s. Not valid format. 
    return Collections.emptyMap(); 
    } 

    // Extract the substrings between | and =, and = and the next |. 
    map.put(payload.substring(start, equalsPos), payload.substring(equalsPos + 1, end)); 

    start = end + 1; 
} 
+0

De cette façon, comment puis-je vérifier si elles sont dans ce format seulement? Si elles ne sont pas dans ce format, retournez la carte vide?Ou devrais-je simplement conclure ceci en essayant d'attraper et il va lancer une exception s'il n'est pas dans ce format et sur la base de cette carte vide? – user1950349

+0

Que voulez-vous dire par "pas dans ce format"? Qu'il y a un '=', puis un '|', puis un '=' etc, avec des caractères entre les deux? Bien sûr: recherchez simplement ceux dans la chaîne en utilisant indexof. –

+0

Oui, il doit être dans ce format seulement et si ce n'est pas le cas, retourner la carte vide. – user1950349

0

Documentation dit que scission va lancer une exception s'il y a des clés en double:

division @CheckReturnValue de la carte publique (séquence CharSequence) de séquence

se sépare en sous-chaînes, chaque sous-chaîne se divise en une entrée, et renvoie une carte non modifiable avec chacune des entrées. Par exemple, Splitter.on (';').. TrimResults() withKeyValueSeparator ("=>") .split ("a => b; c => b") retourne une application de "a" à " b "et" c "à b.

La carte retournée conserve l'ordre des entrées de séquence.

Lancers: IllegalArgumentException - si la séquence spécifiée n'a pas divisé en entrées de carte valides, ou s'il y a des clés en double

Donc, vous ne pouvez pas utiliser la scission de MapSplitter, désolé!

Avec Java 8:

return Splitter 
     .on("|") 
     .splitToList(payload) 
     .stream() 
     .map(kv -> kv.split("=")) 
     .collect(Collectors.toMap(kv -> kv[0], kv -> kv[1], (d1, d2) -> d1)); 
+0

Oui, y a-t-il une meilleure façon de le faire, à l'exception de Splitter? – user1950349

+0

@ user1950349 Peut-être que vous pourriez d'abord corriger votre entrée en utilisant une regex? –

+0

Je suis toujours sur Java 7 malheureusement. – user1950349