I have written a function that checks if a string contains certain words but am not happy with the way the code looks
SO currently i have
private String url = "validator=http://url.com;useraccount=sf4cdamloci;licence=39I8934U401;addedon=343443334;serial=7QW0-5TU8-YN9P-G4FZ;limit=123;days=10"
private String musthave ="validator,useraccount,licence,addedon,serial,limit,days"
So i wanted to check that the url contains the must have words in the string. That eg url must have validator, useraccount, licence.....
SO i have tried the following
Boolean has_validator = false;
Boolean has_licence = false;
.....//others with has_ prefix
String[] split_url = url.split(";")
for(String key_item : split_url){
String[] splitteditem = key_item.split("=");
if (splitteditem[0].equalsIgnoreCase("validator")){
has_validator = true;
}
if (splitteditem[0].equalsIgnoreCase("useraccount")){
has_useraccount = true;
}
....others as well
}
Then later i can easily check
if(has_useraccount && has_...)
The above solution works buts its not scalable as whenever i include a new must have ill have to edit my function.
Is there a better way to achieve this. Am still new to java. I have checked on regex but still i can figure our on how to achieve this.
How do i proceed
Don't use a String to represent a set of Strings. Use... a Set of String: Set<String>. Or at least an array of strings.
Then just use a loop. If any of the word in the set isn't contain in the text, you can immediately return false. If you have never returned false in the loop, then all the words are contained in the text, and you can return true.
Pseudo code:
for each word in the set
if the word is not in the text, return false
end for
return true
If you have a Collection of must-have strings, then you can do something simple like:
mustHave.stream().allMatch(url::contains)
My example isn't doing a case-insensitive check, but you get the idea.
Related
I have list of words which i need to check if any of the words in list is present in string or not but word in the string can be in any format let say i have list of words {:carloan:,creditcard} but in string it can be like car-loan or carloan or :carloan in any of this formats.
I am using lambda function in java to find the any near match but its not working like below:
List<String> list = new ArrayList<>();
list.add(":carloan:")
list.add(":creditcard:")
String inputString = "i want carloan"
boolean match = list.stream().anyMatch(s -> inputString.contains(s));
But above method is giving boolean true only if the substring is matching exactly same with the word in the list.
Is there way i can give true even if it match partially let say the user entered car-loan but in list it's like :carloan: i don't want to use iterate over a list and do matching. Please suggest me way i can do using lambda function in java.
You could use a regex approach here:
List<String> list = new ArrayList<>();
list.add("carloan");
list.add("creditcard");
String regex = ".*(?:" + String.join("|", list) + ").*";
String input = "I am looking for a carloan or creditcard";
if (input.matches(regex)) {
System.out.println("MATCH");
}
Some possible changes you might want to make to the above would be to add word boundaries around the alternation. That is, you might want to use this regex pattern:
.*\b(?:carloan|creditcard)\b.*
This would avoid matching e.g. carloans when you really want to exactly match only the singular carloan.
Edit:
Here is a version using regex closer to your original starting point:
boolean result = list.stream().anyMatch(s -> input.matches(".*\\b" + s + "\\b.*"));
if (result) {
System.out.println("MATCH");
}
We can stream your list of terms, and then assert whether the input string matches any term using regex. But note that this approach means calling String#matches N times, for a list of N terms, while the above approach just makes a single call to that API. I would bet on the alternation approach being more efficient here.
Quick question. I have the following code:
//Cookie
if (mType.getText().toString().toLowerCase().contains("Cookie")) {
mResults.setText(mType.getText().toString().replaceAll("(?i)\\bCookie\\b", "Dough"));
}
//Cola
if (mType.getText().toString().toLowerCase().contains("Cola")) {
mResults.setText(mType.getText().toString().replaceAll("(?i)\\bCola\\b", "Sprite"));
}
I have a script which allows me to replace certain words from user input. When a user inputs the word "Cookie", the script replaces the word with "Dough". If, however, the user types in "Cookie Cola", the script only replaces the word "Cola" with "Sprite" and discards the previous if statement which replaces the word "Cookie".
So, how can I create a script which allows me to replace multiple words from input without discarding previous if statements?
You can just store it into a variable.
like:
String value = (mType.getText().toString().toLowerCase();
if(value.contains("soda")) { value = value.replaceAll("soda","cola"); }
if(...) {...}
But. Technically you are doing more work than necessary. You can chain your replacements.
String value = (mType.getText().toString().toLowerCase();
value = value.replaceAll("soda","cola").replaceAll("...","...")... //Etc.
To answer your question- in both ifs, you're calling replace on mType.getText(). But you aren't changing that value. So you're doing the second replace on the original string. Here's how the code should look like:
String text = mType.getText().toString();
text = text.replaceAll("(?i)\\bCookie\\b", "Dough");
text = text.replaceAll("(?i)\\bCola\\b", "Sprite"));
mResults.setText(text);
Chaining together multiple String.replaceAll() statements can achieve the same result without the need for if statements. For example
String result = mType.getText.toString().toLowerCase();
result = result.replaceAll("cola", "sprite")
.replaceAll("cookie", "dough"); // And so on...
mResults.setText(result);
I've got a List containing String like those :
device0001;sale;2013-01-01 00:00:00;30.45
device0001;sale;2013-01-02 00:00:00;41.02
device0001;sale;2013-01-03 00:00:00;30.45
...
device0001;saleCode;2013-01-01 00:00:00;10
device0001;saleCode;2013-01-02 00:00:00;55
device0001;saleCode;2013-01-03 00:00:00;55
Multiple Device, multiple CodeName and Date by Device. I'd like to map the Value of the saleCode to the sale CodeName.
Example of what I'd like in the end :
device0001;10;2013-01-01 00:00:00;30.45
device0001;55;2013-01-02 00:00:00;41.02
device0001;55;2013-01-03 00:00:00;30.45
The saleCode String may or may not be kept, it doesn't matter.
I've made it work with 2 for loop and ifs, but it was way too long to process.
I thought about building something like this :
Map<String(device), Map<DateTime, Map<String(element), String(value)>>>
forEach device
forEach datetime
element (Codename substring) and replace by element (Value substring)
I'm pretty sure there must be a better and/or elegant way to do this.
EDIT - Since it doesn't seem so clear why I'm trying to do, here is the code with for and if (which is way too slow) :
for (String line : lines) {
if (line.split(SEPARATOR)[4].equals("sale")) {
for (String codeLine : lines) {
if (codeLine.split(SEPARATOR)[5].equals(line.split(SEPARATOR)[5]) &&
codeLine.split(SEPARATOR)[1].equals(line.split(SEPARATOR)[1])&&
codeLine.split(SEPARATOR)[4].equals("saleCode")) {
line = line.replaceAll("sale", codeLine.split(SEPARATOR)[7]);
}
}
}
}
The index doesn't fit with my string's examples only because there are other non important fields, but index [1] is the device number, [5] the date. [4] is the type (sale, saleCode) and [7] the value.
EDIT #2
I've improved the speed like so :
MultiKeyMap<String, String> multiKeyMap = new MultiKeyMap<>();
for (String line : lines) {
if (line.split(SEPARATOR)[4].equals("saleCode")) {
String device = line.split(SEPARATOR)[1];
String date = line.split(SEPARATOR)[5];
String value = line.split(SEPARATOR)[7];
multiKeyMap.put(device, date, value);
}
}
for (int i = 0; i < lines.size(); i++) {
String code = lines.get(i).split(SEPARATOR)[4];
if (code.equals("sale")) {
String device = lines.get(i).split(SEPARATOR)[1];
String date = lines.get(i).split(SEPARATOR)[5];
String newline = lines.get(i).replaceAll("sale", multiKeyMap.get(device, date));
lines.set(i, newline);
}
}
I'll go for that for the moment, but always open for advices.
If I understand your question correctly you don't need to build any maps etc.
You have a list of strings with that format.
Just go over each string and use a regular expression to replace/update each string.
Update:
Your code is slow because you are processing the list over and over for each string.
Create a hashmap based on device id.
Go over the strings in lines one by one.
Check if the string exists on hashmap.
If it does not exist then then check which type of string it is and apply a proper regex for replacement. Add the string to the hashmap
If it does exist then update the string via a regex using the newly encountered string.
When you are done the hashmap will have the strings replaced.
Note: I am mentioning regexes because it seems you have a specific format and it might be written easily and efficiently that way. If you can't use regexes e.g you are not familiar with them follow the approach of parsing it character by character as you are doing. Still it will be better as you process the list once
I'm trying to create a program that can abbreviate certain words in a string given by the user.
This is how I've laid it out so far:
Create a hashmap from a .txt file such as the following:
thanks,thx
your,yr
probably,prob
people,ppl
Take a string from the user
Split the string into words
Check the hashmap to see if that word exists as a key
Use hashmap.get() to return the key value
Replace the word with the key value returned
Return an updated string
It all works perfectly fine until I try to update the string:
public String shortenMessage( String inMessage ) {
String updatedstring = "";
String rawstring = inMessage;
String[] words = rawstring.replaceAll("[^a-zA-Z ]", "").toLowerCase().split("\\s+");
for (String word : words) {
System.out.println(word);
if (map.containsKey(word) == true) {
String x = map.get(word);
updatedstring = rawstring.replace(word, x);
}
}
System.out.println(updatedstring);
return updatedstring;
}
Input:
thanks, your, probably, people
Output:
thanks, your, probably, ppl
Does anyone know how I can update all the words in the string?
Thanks in advance
updatedstring = rawstring.replace(word, x);
This keeps replacing your updatedstring with the rawstring with a the single replacement.
You need to do something like
updatedstring = rawstring;
...
updatedString = updatedString.replace(word, x);
Edit:
That is the solution to the problem you are seeing but there are a few other problems with your code:
Your replacement won't work for things that you needed to lowercased or remove characters from. You create the words array that you iterate from altered version of your rawstring. Then you go back and try to replace the altered versions from your original rawstring where they don't exist. This will not find the words you think you are replacing.
If you are doing global replacements, you could just create a set of words instead of an array since once the word is replaced, it shouldn't come up again.
You might want to be replacing the words one at a time, because your global replacement could cause weird bugs where a word in the replacement map is a sub word of another replacement word. Instead of using String.replace, make an array/list of words, iterate the words and replace the element in the list if needed and join them. In java 8:
String.join(" ", elements);
I want to match certain group of characters in a String independent of their order in the String using regex fucntion. However, the only requirement is that they all must be there.
I have tried
String elD = "15672";
String t = "12";
if ((elD.matches(".*[" + t + "].*"))) {
System.out.println(elD);
}
This one checks whether any of the characters are present. But I want all of them to be there.
Also I tried
String elD = "15672";
String t = "12";
if ((elD.matches(".*(" + t + ").*"))) {
System.out.println(elD);
}
This does not work as well. I have searched quite a while but I could not find an example when all of the characters from the pattern must be present in the String independent of their order.
Thanks
You can write regex for this but it would not look nice. If you would want to check if your string contains anywhere x and y you would need to use few times look-ahead like
^(?=.*x)(?=.*y).*$
and use it like
yourStirng.matches(regex);
But this way you would need to create your own method which would generate you dynamic regex and add (?=.*X) for each character you want to check. You would also need to make sure that this character is not special in regex like ? or +.
Simpler and not less effective solution would be creating your own method which would check if your string contains all searched characters, something like
public static boolean containsUnordered(String input, String searchFor){
char[] characters = searchFor.toCharArray();
for (char c: characters)
if (!input.contains(String.valueOf(c)))
return false;
return true;
}
You can built a pattern from the search string using the replaceAll method:
String s = "12";
String pattern = s.replaceAll("(.)", "(?=[^$1]*$1)");
Note: You can't test the same character several times. (i.e. 112 gives (?=[^1]*1)(?=[^1]*1)(?=[^2]*2) that is exactly the same as (?=[^1]*1)(?=[^2]*2))
But in my opinion Pshemo method is probably more efficient.