Very new to android java and I have a simple question. I have string for example like this :
P:38,AS:31,DT:231,AR:21
I want to split this into 4 different lists in the form :
P(list) = 38
AS(list) = 31
DT(list) = 231
AR(list) = 21
I tried split but it didnt get the job done ...
As long as the keys are always letters and the values are always integers, you can use regular expressions to parse these strings:
Hashtable<String, int[]> result = new Hashtable<String, int[]>();
Pattern pattern = Pattern.compile("([A-Z]+):(\\d+(?:,\\d+)*)");
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
String key = matcher.group(1);
String[] fields = matcher.group(2).split(",");
int[] values = new int[fields.length];
for (int i=0; i<values.length; i++)
values[i] = Integer.parseInt(fields[i]);
result.put(key, values);
}
Edit
"([A-Z]+):(\\d+(?:,\\d+)*)" is a regular expression that matches at least one uppercase letter ([A-Z]+) followed by a colon (:) followed by one more numbers separated by commas (\\d+(?:,\\d+)*). A single number is composed of one more digits (\\d+). The additional parentheses allow us to later access the individual parts of the input string using the group(int) method calls.
The java.util.regex.Matcher class allows us to iterate through the individual parts of the input string that match our regular expression. The find() method returns true as long as there is another substring in our input string that matches the regular expression. So with the input string "P:38,45,AS:31,DT:231,345,678,AR:21" the while loop would execute four times and the matcher variable would point to the following four substrings of the input string:
P:38,45
AS:31
DT:231,345,678
AR:21
We can then use the matcher's group(int) method to access the individual parts of each substring. matcher.group(1) accesses the text that was captured by the first parentheses of our regular expression (([A-Z]+)) which corresponds to "P", "AS", "DT", and "AR" in the individual loop iterations. Analogously, matcher.group(2) corresponds to the second parentheses of the regular expression ((\\d+(?:,\\d+)*)) which would return "38,45", "31", "231,345,678", and "21". So in the first iteration of the while loop key would hold "P" and fields would hold an array of strings ["38", "45"]. We can then parse the fields into actual integer values using Integer.parseInt(String) and store the key and the values in a Hashtable so that we can later retrieve the values for the individual keys. For example, result.get("DT") would return an array of integers with the values [231, 345, 678].
As #pobybolek said, you can use his method which he wrote to take the string and convert it into a hashtable, which uses the key and then the int values after it. The int values are stored in an array and the key is a string.
String input = master_string;
Hashtable<String, int[]> result = new Hashtable<String, int[]>();
Pattern pattern = Pattern.compile("([A-Z]+):(\\d+(?:,\\d+)*)");
Matcher matcher = pattern.matcher(input);
while (matcher.find())
{
String key = matcher.group(1);
String[] fields = matcher.group(2).split(",");
int[] values = new int[fields.length];
for (int pqr=0; pqr<values.length; pqr++)
{
values[pqr] = Integer.parseInt(fields[pqr]);
// values[pqr] = fields[pqr];
}
result.put(key, values);
}
the above code splits the given string into its keys and the values after the key into an integer array, this can also be changed into a String key, String[] array as seen in the second line of my code.
Related
In java I want to iterate an array to find any matching words from my input string
if the input string is appended to numbers it should return true.
Array arr = {"card","creditcard","debitcard"}
String inputStr = "need to discard pin" --> Return False
String inputStr = "need to 444card pin" --> Return True if its followed by number
I tried the below code, but it returns true as it takes "card" from the "discard" string and compares, but I need to do an exact match
Arrays.stream(arr).anymatch(inputString::contains)
Try this:
String[] arr = {"card","creditcard","debitcard"}; // array that keeps the words
String inputStr = "need to discard pin"; // String that keeps the 'sentence'
String[] wordsToBeChecked = inputStr.split(" "); // We take the string and split it at each " " (space)
HashSet<String> matchingWords = new HashSet<>(); // This will keep the matching words
for (String s : arr)
{
for (String s1 : wordsToBeChecked)
{
if(s.equalsIgnoreCase(s1)) // If first word matches with the second
{
matchingWords.add(s1); // add it to our container
}
}
}
Or using Java 8 Streams:
List<String> wordList = Arrays.asList(arr);
List<String> sentenceWordList = Arrays.asList(inputStr.split(" "));
List<String> matchedWords = wordList.stream().filter(sentenceWordList::contains)
.collect(Collectors.toList());
The problem with most answers here is that they do not take punctuation into consideration. To solve this, you could use a regular expression like below.
String[] arr = { "card", "creditcard", "debitcard" };
String inputStr = "You need to discard Pin Card.";
Arrays.stream(arr)
.anyMatch(word -> Pattern
.compile("(?<![a-z-])" + Pattern.quote(word) + "(?![a-z-])", Pattern.CASE_INSENSITIVE)
.matcher(inputStr)
.find());
With Pattern.quote(word), we escape any character within each word with is a special character in the context of a regular expression. For instance, the literal string a^b would never match, because ^ means the start of a string if used in a regular expression.
(?<![a-z-]) and (?![a-z-]) mean that there is not a word character immediately preceding or succeeding the word. For instance, discard will not match, even if it contains the word card. I have used only lowercase in these character classes because of the next bullet:
The flag CASE_INSENSITIVE passed to the compile method causes the pattern to be matched in a case-insensitive manner.
Online demo
You could split the string using a regular expression
String[] arr = {"card","creditcard","debitcard"};
String inputStr = "need to discard pin";
List<String> wordsToBeChecked = Arrays.asList(inputStr.split("[ 0-9]"));
Arrays.stream(arr).anyMatch(wordsToBeChecked::contains);
If your word list and input string is longer, consider splitting your input string into a hashset. Looksups will be faster, then:
Set<String> wordsToBeChecked = new HashSet<>(Arrays.asList(inputStr.split(" ")));
You can create a Set of the words in inputStr and then check the words list against that Set.
Set<String> inputWords = uniqueWords(inputStr);
List<String> matchedWords = Arrays.stream(arr)
.anyMatch(word -> inputWords.contains(word))
.collect(Collectors.toList());
Building the Set may be non-trivial if you have to account for hyphenation, numbers, punctuation, and so forth. I'll wave my hands and ignore that - here's a naive implementation of uniqueWords(String) that assumes they are separated by spaces.
public Set<String> uniqueWords(String string) {
return Arrays.stream(string.split(" "))
.collect(Collectors.toSet());
}
One way would be
String[] arr = {"card","creditcard","debitcard"};
String inputStr = "need to discard pin";
var contains = Arrays.stream(inputStr.split(" ")).anyMatch(word -> Arrays.asList(arr).contains(word));
You can adjust the split regex to include all kinds of whitespace too.
Also: Consider an appropriate data structure for lookups. Array will be O(n), HashSet will be O(1).
I have a String containing a sequence of letters and int numbers A1B12C21D24 I want to create a hashMap with keys the letters from the string and values - the numbers following those letters. So my pairs should be
A 1
B 12
C 21
D 24
I am reading the first letter with charAt(0), the number however can be any number of characters so the only idea I came up with is to take the characters one by one to see if they are numbers store it in another int variable which I to consequently multiply by 10 and add the next number, until I reach a letter char again. This however seems like a lot of looping and I was not sure if there is more efficient way to do it
For example you can do it like this:
Map<String, String> map = new HashMap<>();
Pattern pattern = Pattern.compile("(\\D+)(\\d+)");
Matcher matcher = pattern.matcher("A1B12C21D24 ");
while (matcher.find()) {
map.put(matcher.group(1), matcher.group(2));
}
System.out.println(map);
Output:
{A=1, B=12, C=21, D=24}
You could try String[] pairs = InputString.split("(?=[A-Z])") and then iterate over array with String[] letterAndNumber = pairs[i].split("(?<=[A-Z])")
Then you would just need to save it respectively to HashMap.
More to read about powerful regexp in this answer
I have a string of the following format
A34B56A12B56
And I am trying to sort the numbers into two arrays based on the prefixes.
For example:
Array A: 34,12
Array B: 56,56
What is the simplest way to go about this?
I have tried to use the String Tokenizer class and I am able to extract the numbers, however there is no way of telling what the prefix was. Essentially, I can only extract them into a single array.
Any help would be appreciated.
Thanks!
Andreas seems to have provided a good answer already, but I wanted to practice some regular expressions in Java, so I wrote the following solution that works for any typical alphabetical prefix: (Comments are in-line.)
String str = "A34B56A12B56";
// pattern that captures the prefix and the suffix groups
String regexStr = "([A-z]+)([0-9]+)";
// compile the regex pattern
Pattern regexPattern = Pattern.compile(regexStr);
// create the matcher
Matcher regexMatcher = regexPattern.matcher(str);
HashMap<String, ArrayList<Long>> prefixToNumsMap = new HashMap<>();
// retrieve all matches, add to prefix bucket
while (regexMatcher.find()) {
// get letter prefix (assuming can be more than one letter for generality)
String prefix = regexMatcher.group(1);
// get number
long suffix = Long.parseLong(regexMatcher.group(2));
// search for list in map
ArrayList<Long> nums = prefixToNumsMap.get(prefix);
// if prefix new, create new list with the number added, update the map
if (nums == null) {
nums = new ArrayList<Long>();
nums.add(suffix);
prefixToNumsMap.put(prefix, nums);
} else { // otherwise add the number to the existing list
nums.add(suffix);
}
System.out.println(prefixToNumsMap);
}
Output : {A=[34, 12], B=[56, 56]}
I have a number of large strings looking like this:
"text(24), text_2(5), text_4(822)..."
I'm trying to check if a specific text exists and get the corresponding value.
Is there a quick way to do this?
Edit:
I have an array with all possible text values. At the moment I use foreach to check for text values.
I have the string text_2 and what I need is the corresponding 5 as an integer.
You can use regex to extract all the text element from the String and store them into a map, e.g:
String s = "text(24), text_2(5), text_4(822)";
Pattern pattern = Pattern.compile("([a-zA-Z]*(_)?[0-9]*\\([0-9]+\\))");
Matcher matcher = pattern.matcher(s);
Map<String, Integer> valuesMap = new HashMap<>();
while(matcher.find()){
String[] tokens = matcher.group().split("(?=\\([0-9]+\\),?)");
String key = tokens[0];
Integer value = Integer.parseInt(tokens[1].substring(1, tokens[1].length() - 1));
valuesMap.put(key, value);
}
System.out.println(valuesMap);
Once done, you can call valuesMap.get("test_2"); to get the corresponding value. This is how the above example works:
It splits text into tokens containing <text>(<Value)
It then splits each token again, into text and value and places these into a Map.
Since you need to do this a number of times. I suggest you split the string and build a map from the text to its value, this is O(n). After that, your lookups are only O(1) if you use HashMap.
String text = "text(24), text_2(5), text_4(822)";
Map<String, Integer> map = new HashMap<>();
String[] split = text.split(", ");
for(String s:split){
//search for the position of "(" and ")"
int start = 0;
int end = s.length()-1;
while(s.charAt(start) != '(')
start++;
while(s.charAt(end) != ')')
end--;
//put string and matching value in the map
map.put(s.substring(0, start), Integer.parseInt(s.substring(start+1, end)));
}
System.out.println(map);
I also ran some benchmarks for a string containing 10000 entries. And this approach was about 4 times faster than a regex approach. (38 ms vs 163 ms)
I have a series of strings, each of the format :
"{3.242, 87611}, {5.658, 7.3731}, {5.547, 8.7631} ......"
Each pair of numbers in curly brackets represents one Latitude/Longitude point (and each number is of type double).
I want to parse the string so that each point in the string is represented as a separate Lat/Lon object, that I store in a list of points.
I am pretty new to Java (and parsing). I have been looking at a lot of examples but I'm still really confused as to how to even begin.
How do I go about doing this?
You can use regExp to fetch points first,
String str = "{3.242, 87611},{5.658, 7.3731}";
Pattern pattern = Pattern.compile("\\{(.*?)\\}");
Matcher match = pattern.matcher(str);
while(match.find()) {
System.out.println(match.group(1));
}
OUTPUT
3.242, 87611
5.658, 7.3731
Now you can just use split to find two points and you can parse them to Double. Note here (.*?) is a group which means any String
Assuming you have already have this String in some variable str, you can split str into it's component numbers
String[] splitNumbers = str.split("[{}, ]+");
then iterate over this list and use each pair of numbers to construct a Coordinate object.
Coordinate[] coords = new Coordinate[splitNumbers.length/2];
for(int i=0; i < splitNumbers.length-2;i+=2){
double longitude = Double.paresDouble(splitNumbers[i]);
double latitude = Double.paresDoublesplitNUmbers[i+1]);
coords[i/2] = new Coordinate(longitude,latitude);
}