How to search a string of key/value pairs in Java - 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"?

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

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"...
}
}

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.

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.

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]

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

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]

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

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

Related

Given string filter a part of it based on a pattern then add to array-list

Given a string with repeating pattern here:
String s = NameJJ,ABC/firstname,120, NameBB,ABC/secondname,100,NameCC,ABC/thirdname,150,NameJJ,ABC/firstname,200,NameBB,ABC/secondname,300,NameCC,ABC/thirdname,500
Essentially I want way where when NameJJ and firstname are beside each other like at top it stores value beside them which is arraylist1 = [120,200].
Essentially I want way where all field with NameBB and secondname are beside each other to store the value beside them which is arraylist2 = [100,300].
Essentially I want way where all field with NameJJ and thirdname are beside each other to store the value beside them which is arraylist3 = [150,500].
I was trying to do this to say if string contains NameJJ and contains firstname should filter out value beside it but I'm confused on how I would do that, this is the code :
if (s.contains(NameJJ) && s.contains(firstname))
Pattern reg = Pattern.compile(",");
ArrayList<String> SANR = reg.splitAsStream(s)
.filter(role -> role.contains(""))
.map(String::trim)
.collect(Collectors.toCollection(ArrayList::new));
Your String s holds the complete data so if (s.contains(NameJJ) && s.contains(firstname)) will always be true.
You have to split the blocks first, then look at the values.
Your data block contains 3 data each so that's the number you have to divide by in loop condition and multiply with in array access
String s = "NameJJ,ABC/firstname,120, NameBB,ABC/secondname,100,NameCC,ABC/thirdname,150,NameJJ,ABC/firstname,200,NameBB,ABC/secondname,300,NameCC,ABC/thirdname,500";
String[] split = s.split(",");
List<Integer> first = new ArrayList<>();
List<Integer> second = new ArrayList<>();
List<Integer> third = new ArrayList<>();
for (int i = 0; i < split.length / 3; i++) {
// first data block is Name..
// second block is firstname/secondname/thirdname
// third block hold the number you want
if (split[3 * i].trim().equals("NameJJ") && split[3 * i + 1].trim().equals("ABC/firstname")) {
first.add(Integer.parseInt(split[3 * i + 2].trim()));
} else if (split[3 * i].trim().equals("NameBB") && split[3 * i + 1].trim().equals("ABC/secondname")) {
second.add(Integer.parseInt(split[3 * i + 2].trim()));
} else if (split[3 * i].trim().equals("NameCC") && split[3 * i + 1].trim().equals("ABC/thirdname")) {
third.add(Integer.parseInt(split[3 * i + 2].trim()));
}
}
System.out.println(first);
System.out.println(second);
System.out.println(third);
Output is
[120, 200]
[100, 300]
[150, 500]
As I've answered in a previous question of yours, whenever you're having a certain pattern repeating itself, you should use a regex to extract the sub-bits of your pattern.
Streams are not designed to keep track of a "first" or "last" element. They're mainly stateless operations, with a few exceptions for distinct, sorted and similar. Stateless operations start their execution even before the previous one has finished its computation. This is why they have no recollection of a first or last result and also why we cannot use them for this kind of tasks.
What you could do is to employ 3 regex to match your pattern for nameJJ, nameBB and nameCC, and use capturing groups to identity and extract every desired sub-bit.
The following 3 regex can be used to match your patterns:
(\w+)JJ,(\w+)\/(\w+),(\d+)
(\w+)BB,(\w+)\/(\w+),(\d+)
(\w+)CC,(\w+)\/(\w+),(\d+)
Here is a snippet of the code implementation:
public class Main {
public static void main(String[] args) {
String s = "NameJJ,ABC/firstname,120, NameBB,ABC/secondname,100,NameCC,ABC/thirdname,150,NameJJ,ABC/firstname,200,NameBB,ABC/secondname,300,NameCC,ABC/thirdname,500";
List<Integer> listNameJJ = getList("(\\w+)JJ,(\\w+)\\/(\\w+),(\\d+)", s);
List<Integer> listNameBB = getList("(\\w+)BB,(\\w+)\\/(\\w+),(\\d+)", s);
List<Integer> listNameCC = getList("(\\w+)CC,(\\w+)\\/(\\w+),(\\d+)", s);
System.out.println(listNameJJ);
System.out.println(listNameBB);
System.out.println(listNameCC);
}
public static List<Integer> getList(String regex, String str) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
List<Integer> list = new ArrayList<>();
while (matcher.find()) {
list.add(Integer.valueOf(matcher.group(4)));
}
return list;
}
}
Here is also a link to test the code above:
https://ideone.com/TES5UY
Here is another example,
public class Application {
public static void main(String[] args) {
String yourString = "NameJJ,ABC/firstname,120, NameBB,ABC/secondname,100,NameCC,ABC/thirdname,150,NameJJ,ABC/firstname,200,NameBB,ABC/secondname,300,NameCC,ABC/thirdname,500";
String myString = "NameKK,ZXY/kname,510, NameQQ,HLM/kname,210, NameKK,ZXY/kname,210,";
// Test 1
System.out.println(getValues("NameJJ", "firstname", yourString));
// Test 2
System.out.println(getValues("NameKK", "kname", myString));
}
private static List<Integer> getValues(String str1, String str2, String inputString) {
// Note* List is an ordered sequence of elements.
List<Integer> value = new ArrayList<Integer>();
// Extract Values
Matcher m = Pattern.compile("-?\\d+(,\\d+)*?\\.?\\d+?")
.matcher(inputString);
while (m.find()) {
value.add(Integer.parseInt(m.group().trim()));
}
// Extract Keys
List<String> key = List.of(inputString.split("\\d+"));
List<Integer> result = new ArrayList<Integer>();
// Filtering
for (int i = 0; i < value.size(); i++) {
if (key.get(i).trim().contains(str1)
&& key.get(i).trim().contains(str2)) {
result.add(value.get(i));
}
}
return result;
}
}
Console O/P:
[120, 200]
[510, 210]

How to get only the digits from list of string using java

I have list with combination of letters, digits and special characters. I need to extract the digits from string and store them in the same list.
I tried with below code
List<String> list = new LinkedList<String>();
list.add("132144, Test");
list.add("76876295, Test2");
//tried with replaceAll();
list.replaceAll(x->x.replace("[^0-9]",""));
//tried collection
Collections.replaceAll(list, "\\W+", "");
System.out.println(list);
Getting the output as [132144, Test,76876295, Test2], need output as [132144,76876295]
Stream the list, map each entry using a regular expression (\\D matches non-digits) to replace all non-digits with nothing. Collect that back into your original list (assuming you need to keep the new values only). Like,
list = list.stream().map(s -> s.replaceAll("\\D+", ""))
.collect(Collectors.toList());
System.out.println(list);
Outputs (as requested)
[132144, 768762952]
Your current input doesn't have such a case, but you might also filter out any empty String(s) after applying the regex.
list = list.stream().map(s -> s.replaceAll("\\D+", ""))
.filter(s -> !s.isEmpty()).collect(Collectors.toList());
You can do like this:
String line = "This order was32354 placed OK?8377jj";
String regex = "[^\\d]+";
String[] str = line.split(regex);
for(int i=0;i<str.length; i++) {
System.out.println(str[i]);
}
Output:
32354
8377
Hope this helps.
public static void main(String[] args) {
List<String> list = new LinkedList<String>();
List<String> list1 = new LinkedList<String>();
list.add("132144, Test");
list.add("76876295, Test2");
for(String s:list)
list1.add(retriveDigits(s));
System.out.println(list1);
}
private static String retriveDigits(String str) {
return str.replaceAll("[^0-9]*", "");
}
}
Please find above class, I think that will help you.
you can use NumberUtils.isNumber() in stream like this:
list = list.stream()
.filter(NumberUtils::isNumber)
.collect(Collectors.toList());

Filter Java list and create integer constants array

I have a Java list of Strings as below:
myList:
C26366
C10025, C10026
C10244
C26595
C26594
C9026, C9027, C9029, C9080 //this is one list element (needs seperation)
C26597
C10223, C10287, C10277, C10215
C10242
C10243
C9025, C9030, C9034, C9051, C9052, C9055 // similarly here
C10241
C10067
C27557
C10066
.... //these are all ids
Above is an output of below for-loop snippet:
for (String id: myList) {
System.out.println(id);
}
How do I convert this myList into a Java integer array? I am expecting something like/I want to use use that array as:
public static final IDS = { 31598,9089,9092,9093,9108,9109,....}
IDS array must hold the content from myList and they are without any C's in them and no other characters, but just the numbers.
In Java 8 you can use streams:
List<String> myList = Arrays.asList(
"C26366", "C10025, C10026", "C10244", "C26595", "C26594",
"C9026, C9027, C9029, C9080", "C26597", "C10223, C10287, C10277, C10215",
"C10242", "C10243",
"C9025, C9030, C9034, C9051, C9052, C9055", "C10241", "C10067");
List<Integer> myListOfIntegers = myList.stream()
.map(x -> x.split(","))
.flatMap(l -> Arrays.asList(l).stream())
.map(y -> y.replaceAll("\\D", ""))
.map(z->Integer.parseInt(z))
.collect(Collectors.toList());
for( Integer i : myListOfIntegers ){
System.out.println(i);
}
a result is:
26366
10025
10026
10244
26595
26594
9026
9027
9029
9080
26597
10223
10287
10277
10215
10242
10243
9025
9030
9034
9051
9052
9055
10241
10067
I would suggest to do this:
Define a list of integers for the final values
then use Regex with this pattern "\d+" to find in the list of strings only the things that are numeric
if found, parse it to integer and add it to the list.
Example:
List<Integer> myListIntegers = new ArrayList<Integer>();
for (String subStrings : myList) {
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(subStrings);
while (m.find()) {
myListIntegers.add(Integer.parseInt(m.group()));
}
}
System.out.println(myListIntegers);
this code will print the list holding the insteger you have in myList
[26366, 10025, 10026, 10244, 26595, 26594, 9026, 9027, 9029, 9080,
10241, 10067, 27557, 10066]

Java equivalent for PHP preg_grep

Could somebody tell me if a Java equivalent exist for PHP preg_grep()? Or supply me with a good way to accomplish the same?
I need to do string matching against element in input array and return array with input array's indexes as preg_grep() does.
There is no exact equivalent. But you can use the String#matches(String) function to test if a string matches a given pattern. For example:
String s = "stackoverflow";
s.matches("stack.*flow"); // <- true
s.matches("rack.*blow"); // <- false
If you want a result array with the matching indices, you can loop over your given input array of strings, check for a match and add the current index of the loop to your result array.
You could use this kind of function, using String.matches() and iterating over your array :
public static List<Integer> preg_grep(String pattern, List<String> array)
{
List<Integer> indexes = new ArrayList<Integer>();
int index = 0;
for (String item : array) {
if (item.matches("ba.*")) {
indexes.add(index);
}
++index;
}
return indexes;
}
Ideone Example
How about something like:
private static String[] filterArrayElem(String[] inputArray) {
Pattern pattern = Pattern.compile("(^a.*)");
List<String> resultList = new ArrayList<>();
for (String inputStr : inputArray) {
Matcher m = pattern.matcher(inputStr);
if (m.find()) {
resultList.add(m.group(0));
}
}
return resultList.toArray(new String[0]);
}
You can then use it in the following way:
String [] input = { "apple", "banana", "apricot"};
String [] result = filterArrayElem(input);

Java: Convert List<Integer> to String

How can I convert List<Integer> to String? E.g. If my List<Integer> contains numbers 1 2 and 3 how can it be converted to String = "1,2,3"? Every help will be appreciated.
I think you may use simply List.toString() as below:
List<Integer> intList = new ArrayList<Integer>();
intList.add(1);
intList.add(2);
intList.add(3);
String listString = intList.toString();
System.out.println(listString); //<- this prints [1, 2, 3]
If you don't want [] in the string, simply use the substring e.g.:
listString = listString.substring(1, listString.length()-1);
System.out.println(listString); //<- this prints 1, 2, 3
Please note: List.toString() uses AbstractCollection#toString method, which converts the list into String as above
In vanilla Java 8 (streams) you can do
// Given numberList is a List<Integer> of 1,2,3...
String numberString = numberList.stream().map(String::valueOf)
.collect(Collectors.joining(","));
// numberString here is "1,2,3"
With Guava:
String s = Joiner.on(',').join(integerList);
One way would be:
Iterate over list, add each item to StringBuffer (or) StringBuilder and do toString() at end.
Example:
StringBuilder strbul = new StringBuilder();
Iterator<Integer> iter = list.iterator();
while(iter.hasNext())
{
strbul.append(iter.next());
if(iter.hasNext()){
strbul.append(",");
}
}
strbul.toString();
Just to add another (of many) options from a popular library (Apache Commons):
import org.apache.commons.lang3.StringUtils;
String joinedList = StringUtils.join(someList, ",");
See documentation: https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#join-java.lang.Iterable-java.lang.String-
An elegant option from others' comments (as of Java 8):
String joinedList = someList.stream().map(String::valueOf).collect(Collectors.joining(","));

Categories