user438293456
user438293456

Reputation: 596

How to search a string of key/value pairs in Java

I have a String that's formatted like this:

"key1=value1;key2=value2;key3=value3"

for any number of key/value pairs.

I need to check that a certain key exists (let's say it's called "specialkey"). If it does, I want the value associated with it. If there are multiple "specialkey"s set, I only want the first one.

Right now, I'm looking for the index of "specialkey". I take a substring starting at that index, then look for the index of the first = character. Then I look for the index of the first ; character. The substring between those two indices gives me the value associated with "specialkey".

This is not an elegant solution, and it's really bothering me. What's an elegant way of finding the value that corresponds with "specialkey"?

Upvotes: 6

Views: 34826

Answers (9)

Rolud
Rolud

Reputation: 154

Try this:

List<Integer> results = new ArrayList();

Pattern p = Pattern.compile("(?:(?:A=)([^,]*))");
Matcher m = null;
     
for (String tmp : OriginalList) {
    m = p.matcher(tmp);
    if (m.find()) {
     int r = Integer.parseInt(m.group(0).replace("A=", ""));
        results.add(r);
    }
        
}

Upvotes: 0

Kawser Habib
Kawser Habib

Reputation: 1422

Using basic filter: Split using [A-Z=,]+ regex. Pick the 2nd element.

public List filter() {
        List<String> originalList = Arrays.asList("A=1,B=2,C=3", "A=11,B=12,C=13,D=15", "A=5,B=4,C=9,D=10,E=13",
                "A=19,B=20,C=91,D=40,E=33", "A=77,B=27,C=37");
        List<Integer> parsedData = new ArrayList();
        
        for(String str: originalList) {
            Integer data = Integer.parseInt(str.split("[A-Z=,]+")[1]);
            parsedData.add(data);
            
        }
        return parsedData;
        
}

Upvotes: 0

Mike Sickler
Mike Sickler

Reputation: 34451

I would parse the String into a map and then just check for the key:

String rawValues = "key1=value1;key2=value2;key3=value3";
Map<String,String> map = new HashMap<String,String>();
String[] entries = rawValues.split(";");
for (String entry : entries) {
  String[] keyValue = entry.split("=");
  map.put(keyValue[0],keyValue[1]);
}

if (map.containsKey("myKey")) {
   return map.get("myKey");
}

Upvotes: 13

Nowhere Man
Nowhere Man

Reputation: 19565

This may be implemented using Stream API by simple splitting of each string in the input list by comma and Stream::flatMap

// assuming A is not always at the beginning
List<String> list = Arrays.asList(
        "A=1,B=2,C=3",
        "A=11,B=12,C=13,D=15",
        "A=5,B=4,C=9,D=10,E=13",
        "B=20,C=91,D=40,E=33",
        "B=27, A=19, C=37, A=77");

List<Integer> aNums = list.stream() // Stream<String>
    .flatMap(
        s -> Arrays.stream(s.split("\\s*,\\s*")) // Stream<String> pairs of letter=digits
                   .filter(pair -> pair.startsWith("A="))
                   .map(pair -> Integer.valueOf(pair.substring(2)))
    )
    .collect(Collectors.toList());
System.out.println(aNums);

Output:

[1, 11, 5, 19, 77]

Update
A pattern to split an input string and keep only the digits related to A may be applied as follows:

Pattern splitByA = Pattern.compile("A\\s*=\\s*|\\s*,\\s*|[^A]\\s*=\\s*\\d+");
List<Integer> aNums2 = list.stream()
    .flatMap(splitByA::splitAsStream) // Stream<String>
    .filter(Predicate.not(String::isEmpty)) // need to remove empty strings
    .map(Integer::valueOf)
    .collect(Collectors.toList());
System.out.println(aNums2);

Output is the same

[1, 11, 5, 19, 77]

Upvotes: 0

WJS
WJS

Reputation: 40062

There are many ways to do this. Perhaps the simplest is to use the Streams API (available as of Java 8 and later) to process the match results:

List<String> OriginalList = Arrays.asList("A=1,B=2,C=3",
        "A=11,B=12,C=13,D=15", "A=5,B=4,C=9,D=10,E=13",
        "A=19,B=20,C=91,D=40,E=33", "A=77,B=27,C=37");
  • this streams the strings
  • matches on the pattern and extracts the integer
  • the collects to a list
Pattern p = Pattern.compile("A=(\\d+)");
List<Integer> result = OriginalList.stream().
        flatMap(str->p.matcher(str).results())
        .map(mr->Integer.valueOf(mr.group(1)))
        .collect(Collectors.toList());

System.out.println(result);

Prints:

[1, 11, 5, 19, 77]

Upvotes: 1

user6223604
user6223604

Reputation:

Try : (?:(?:A=)([^,]*))

Demo : https://regex101.com/r/rziGDz/1

Else you find a code using regex and your list to get answer :

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.*;
    
public class Main 
{
    public static void main(String[] args) 
    {
      
    List<Integer> results = new ArrayList();
    Pattern pattern = Pattern.compile("(?:(?:A=)([^,]*))", Pattern.CASE_INSENSITIVE);
    List<String> OriginalList = Arrays.asList(
            "A=1,B=2,C=3",
            "A=11,B=12,C=13,D=15",
            "A=5,B=4,C=9,D=10,E=13",
            "A=19,B=20,C=91,D=40,E=33",
            "A=77,B=27,C=37");
            
        for (int i = 0; i < OriginalList.size(); i++) 
        {
            Matcher matcher = pattern.matcher(OriginalList.get(i));
            boolean matchFound = matcher.find();
            if(matchFound) 
            {
                System.out.println( matcher.group(1) );
                results.add( Integer.parseInt(matcher.group(1)) );
            }
        }
    }
}

Upvotes: 0

asgs
asgs

Reputation: 3984

Just in case anyone is interested in a pure Regex-based approach, the following snippet works.

Pattern pattern = Pattern.compile("([\\w]+)?=([\\w]+)?;?");
Matcher matcher = pattern.matcher("key1=value1;key2=value2;key3=value3");
while (matcher.find()) {
   System.out.println("Key - " + matcher.group(1) + " Value - " + matcher.group(2);
}

Output will be

Key - key1 Value - value1
Key - key2 Value - value2
Key - key3 Value - value3

However, as others explained before, String.split() is recommended any day for this sort of task. You shouldn't complicate your life trying to use Regex when there's an alternative to use.

Upvotes: 2

mathematical.coffee
mathematical.coffee

Reputation: 56935

If it's just the one key you're after, you could use regex \bspecialkey=([^;]+)(;|$) and extract capturing group 1:

Pattern p = Pattern.compile("\\bspecialkey=([^;]+)(;|$)");
Matcher m = p.matcher("key1=value1;key2=value2;key3=value3");

if (m.find()) {
    System.out.println(m.group(1));
}

If you're doing something with the other keys, then split on ; and then = within a loop - no need for regex.

Upvotes: 5

icyrock.com
icyrock.com

Reputation: 28618

Use String.split:

String[] kvPairs = "key1=value1;key2=value2;key3=value3".split(";");

This will give you an array kvPairs that contains these elements:

key1=value1
key2=value2
key3=value3

Iterate over these and split them, too:

for(String kvPair: kvPairs) {
   String[] kv = kvPair.split("=");
   String key = kv[0];
   String value = kv[1];

   // Now do with key whatever you want with key and value...
   if(key.equals("specialkey")) {
       // Do something with value if the key is "specialvalue"...
   }
}

Upvotes: 9

Related Questions