2010-08-27 3 views
2

Je suis en train d'établir une certaine façon de mapper un document de chaîne à un HashMap comme suit:Mapping contenu CORDE paires clé/valeur à un HashMap

la chaîne contient une paire clé/valeur

$key1=value1 
$key2=value2 value21 
value22 
$key3=value3 

ce que je veux finir avec est:

key1, value1 
key2, value2 value21\nvalue22 
key3, value3 

Y at-il un modèle que je peux utiliser pour cela? Cela ressemble à un casse-tête intéressant, jusqu'à présent j'ai utilisé pour séparer les différentes valeurs, mais ensuite il doit y avoir une itération différente pour identifier les clés, donc je cherche une solution plus élégante.

+0

ne vous embêtez pas avec '{1}' spécificateur de répétition. http: // stackoverflow.com/questions/3032593/using-explicitement-numéroté-répétition-au lieu-de-question-marque-étoile-et-plus – polygenelubricants

Répondre

1

Vous devez utiliser deux regex ici:
\$(\w+)=((\w+\s*)+) va séparer les clés des valeurs
(\s+) pour diviser les valeurs.

String input = "$key1=value1\n" + 
     "$key2=value2 value21\n" + 
     "value22\n" + 
     "$key3=value3"; 

Pattern keyValuePattern = Pattern.compile("\\$(\\w+)=((\\w+\\s*)+)"); 
Matcher keyValueMatcher = keyValuePattern.matcher(input); // get a matcher object 
Map<String, List<String>> map = new HashMap<String, List<String>>(); 
while (keyValueMatcher.find()) { 
    String key = keyValueMatcher.group(1); 
    List<String> values; 
    values = Arrays.asList(keyValueMatcher.group(2).split("\\s+")); 
    //If you want to update your lists later comment the line above and uncomment those two 
    //values = new ArrayList<String>(); 
    //values.addAll(Arrays.asList(keyValueMatcher.group(2).split("\\s+"))); 

    map.put(key, values); 
} 

System.out.println(map); // {key3=[value3], key2=[value2, value21, value22], key1=[value1]} 

NB: Vous pouvez utiliser \$(\w+)=(.*) comme regex aussi, cela dépend de ce que vous voulez faire correspondre, dans le cas ci-dessus, chaque mot/nombre séparés par des espaces, dans ce cas, quoi que ce soit.

1

Probablement vous pouvez jeter un oeil aux fichiers Properties.

Vous pouvez utiliser le Properties.load(InputStream) pour lire les entrées de fichiers à l'aide:

Properties properties = new Properties(); 
properties.load(this.getClass().getClassLoader() 
    .getResourceAsStream("file.properties")); 

ou même d'une chaîne en utilisant:

String myString = new String("first=1"); 
Properties properties = new Properties(); 
properties.load(new StringBufferInputStream(myString)); 

Vous pouvez trouver plus d'informations sur la mise en forme dans le Properties.load(InputStream) doc.

0

En supposant, le texte complet est dans une chaîne (= pas ligne de lecture par ligne), vous pouvez travailler avec plusieurs divisions:

String input = "$key1=value1\n$key2=value2 value21\nvalue22\n$key3=value3"; 
String[] lines = input.split("\n"); 
Map<String, String> map = new HashMap<String, String>(); 


StringBuilder value = null; 
String key = null; 
for (String line:lines) { 
    if (line.contains('=')) { 
    if (key != null) { 
     // store the actual k/v pair before starting a new one 
     map.put(key, value.toString()); 
    } else { 
     // create a new k/v pair 
     String[] temp = line.split("="); 
     key = temp[0]; 
     value = new StringBuilder(temp[1]); 
    } 
    } else { 
    // we have a value that belongs to the last k/v pair 
    value.append("\n").append(line); 
} 
map.put(key, value.toString()); 

La solution pourrait avoir besoin de quelques ajustements, mais devrait fonctionner en principe.

+0

C'est à peu près ce que j'ai en ce moment et ça ne marche pas. Dans l'exemple ci-dessus keyValuePairs [2] ne contient pas de clé $ = En tout cas, j'apprécie votre réponse. – heeboir

+0

... désolé, mon erreur. Je vais trouver la bonne solution, attendez, s'il vous plaît. –

+0

... c'est mieux. Nous stockons une paire de k/v après que nous sommes sûrs, nous avons lu tous les chars pour la valeur. Une nouvelle ligne contenant une clé déclenche le stockage de la précédente. –

0

Vous devez être clair exactement quelles sont vos limites et délimiteurs. Dans le cas de votre exemple, je suppose que les délimiteurs sont les $ au début de la ligne qui est suivie par un "mot" (composé de \w caractères) puis un symbole =.

Si nous faisons une hypothèse simplificatrice et dire qu'un $ au début de la ligne est le délimiteur (quel que soit ce qui suit), nous pouvons faire quelque chose comme ceci:

(?xms: # Switch on "x" (comment-mode), "m" (Allow "^" to mean start of line rather than start-of-input), "s" (dot-all) 
^\$ # Match $ at start of line only 
    ([^=]+) # Then capture everything until the next '=' (you may want to use \w+ here) 
    =   # Skip the = 
    (
    (?: 
     (?! \n (?:^\$ | \z)) # Stop if we reach the \n before the next $ at the start of a line or the \n at the end of the input 
     .   # Otherwise accept any character (including \n thanks to dot-all mode) 
    ) * 
    ) # This will capture everything (excluding the trailing newline) up to the next $ at the start of the line (or all the way to the end of the input) 
) 

Vous pouvez alors utiliser cette dans une boucle:

static final Pattern pattern = Pattern.compile(" <the above RE> "); 
    . . . 
Matcher matcher = pattern.matcher(myInputString); 
while (matcher.find()) { 
    map.put(matcher.group(1), matcher.group(2)); 
} 

(je ne l'ai pas testé tout cela du tout, mais il devrait vous aider à démarrer)