I am trying to implement a functionality in android app where as user keys in the numbers, I want to incrementally search those numbers in Phone book (the generic phone book search) and display result.
For this, I am using
Uri.withAppendedPath(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, Uri.encode(aNumber));
This seems to work for most of the cases and is handling search for ' ' etc.
There are 2 issues that I am not able to resolve :
It does not ignore the country code.
So as an e.g. if I have a number : +9199776xx123
When my search string is +9199, the result comes up. While if my search string is 9977, it does not come up.
It does not search from between.
When my search string is 776, then also result does not come up.
So the behavior of CONTENT_FILTER_URI of Phone is not exactly clear to me.
P.S. : I have tried PhoneLookup but for some reason, it does not throw any result. My belief is that it might not be capable to searching partial numbers.
After quite a lot or research, I was able to find the answer. Now, I search on both the columns, Number and normalized number. This takes care of both the cases since normalized number contains country code in the number.
My selection string looks like :
String selection = ContactsContract.CommonDataKinds.Phone.NUMBER + " LIKE ? OR "
+ ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER + " LIKE ?";
Phone.CONTENT_FILTER_URI is built for speed, but it's not perfect, as you've noticed.
You can use the plain Phone.CONTENT_URI to process any kind of request you want.
e.g.:
String partialPhone = "9977";
String[] projection = new String[] {Phone.DISPLAY_NAME, Phone.NUMBER, Phone. NORMALIZED_NUMBER};
String selection = "(" + Phone.NUMBER + " LIKE %" + partialPhone + "%) OR (" + Phone.NORMALIZED_NUMBER + " LIKE %" + partialPhone + "%)";
Cursor c = cr.query(Data.CONTENT_URI, projection, selection, null, null);
Related
I'm currently building a REST API in spring, and would like to add a search method which takes in a list of letters and search for sequences based on those letters. The code I have below is an example of what i've achieved so far. It does the job, and searches based on the letter parameters. But it's limited to have to use exactly the number of params specified in the method.
#Query("SELECT f FROM Item f " +
"WHERE LOWER(f.title) LIKE CONCAT(" +
" '%',LOWER(:letter1)," +
" '%',LOWER(:letter2)," +
" '%',LOWER(:letter3)," +
" '%',LOWER(:letter4),'%')")
#RestResource(rel = "title-fragmented", path="findByFragments")
Page<Item> findByFragmented(#Param("letter1") String letter1,
#Param("letter2") String letter2,
#Param("letter3") String letter3,
#Param("letter4") String letter4,
Pageable page
);
I was wondering if it is possible to achieve the same result without specifying the number of letters to be concatenated. So for example when
/api/v1/search/findByfragments?letter=A&letter=B&letter=C....
is called, it'll work. I've tried passing string arrays as a the #Param value, but couldn't get it to work.
Thanks in advance.
Solved my issue by using SpEL expressions to split apart a single string, and replace the letters between them with wildcard(%) expression. Example below for anyone who may find themselves with the same issue:
#Query(
"SELECT f FROM Item f WHERE LOWER(f.title) LIKE CONCAT('%',LOWER(:#{#title.replaceAll('','%')}),'%')"
)
#RestResource(rel = "item-title-by-fragments", path="fragments")
Page<Item> findUsingFragments(#Param("title") String title, Pageable page);
How to strip a string like this:
String a = "ItemStack{DIAMOND_HELMET x 1,UNSPECIFIC_META:{meta-type=UNSPECIFIC, display-name=PRO, repair-cost=1}}"
I want to get something like
"Diamond_HELMET 1 UNSPECIFIC PRO"
The methods I have tried is just replacing a bunch of strings, but its a pain in the *** and looks awful. Just wondering if anyone have a better solution/option.
Sorry forgot to add my own code :/
String itemStackStringName = "ItemStack{DIAMOND_HELMET x 1, UNSPECIFIC_META:{meta-type=UNSPECIFIC, display-name=PRO, repair-cost=1}}";
String getItemStacks = itemStackStringName.replace("ItemStack","")
.replace("{","").replace("}", "").replace("UNSPECIFIC_META:", "")
.replace("display-name", "").replace("=","")
.replace("meta-type", "").replace("repair-cost1", "")
.replace("x", "").replace(",","");
System.out.println(getItemStacks);
"DIAMOND_HELMET 1 UNSPECIFIC PRO"
It works, but its just a huge mess.
If you know that's the type your strings are going to be, you can go ahead and do something like this:
String arr[] = a.split("\\{");//you get an array of 3 strings
String someFinalString = arr[1].split("x")[0].trim();//you get "DIAMOND_HELMET"
someFinalString += arr[1].split("x")[1].split(",")[0];
arr = arr[2].split("\\=");//you get an array of 4 strings
someFinalString += " " + arr[1].split(",")[0] + " " + arr[2].split(",")[0];
In the future please post what you tried to do. Splitting something like this will always look awful. You can always make it concise later.
Just a proof this works (and you can figure out by yourself how to get lowercase I guess):
I created this Java method:
public String isInTheList(List<String> listOfStrings)
{
/*
* Iterates through the list, and if the list contains the input of the user,
* it will be returned.
*/
for(String string : listOfStrings)
{
if(this.answer.matches("(?i).*" + string + ".*"))
{
return string;
}
}
return null;
}
I use this method in a while block in order to validate user input. I want to check if that input matches the concatenation of two different predefined ArrayLists of Strings.
The format of the input must be like this:
(elementOfThefirstList + " " + elementOfTheSecondList)
where the Strings elementOfThefirstList and elementOfTheSecondList are both elements from their respective list.
for(int i = 0; i < firstListOfString.size(); i++)
{
if(userInput.contains(firstListOfString.get(i) + " " + userInput.isInTheList(secondListOfString)))
{
isValid = true;//condition for exit from the while block
}
}
It work if the user input is like this:
elementOfThefirstList + " " + elementOfTheSecondList
However, it will also work if the user input is like this:
elementOfThefirstList + " " + elementOfTheSecondList + " " + anotherElementOfTheFirstList
How can I modify my regular expression, as well as my method, in order to have exactly one repetition of elements in both lists concatenated with a space between them?
I tried with another regular expression and I think that I will use this: "{1}". However, I am not able to do that with a variable.
With the information you provide as to how you are getting this issue, there is little that can be said about how to fix it. I strongly encourage you to look at this quantifiers tutorial before moving forward.
Let's look at some solutions.
For example, lets look at the line:if(this.answer.matches("(?i).*" + string + ".*"))What you are trying to do is to see if this.answer contains string, ignoring case (I doubt you need the last .*). But you are using a Greedy Quantifier to compare them. If the issue is arising due to an input error in this comparison, I would consider looking at the linked tutorial for Reluctant Quantifiers.
Okay, so it wasn't a quantifier issue. The other possible fix may be this block of code:
for(int i = 0; i < firstListOfString.size(); i++)
{
if(userInput.contains(firstListOfString.get(i) + " " + userInput.isInTheList(secondListOfString)))
{
isValid = true;//condition for exit from the while block
}
}
I don't know you you got userInput to have the containsmethod, but I assume that you used containment to call the String method. If this is the case, there could be a solution to the issue. You would only have to state that it is valid if and only if it is equal to an element from the first list and a matching element from the second string.
The final solution I have for you is simple. If there are no other spaces present within the list elements, you could split the concatenated String on a space and check how many elements the resulting array contains. If it is greater than two, then you have an invalid concatenation.
Hopefully this helps!
I am working on a Plugin, and came across this bug that makes no sense to me. I have a List that contains multiple strings, and when checking if it contains it use .contains it returns false in my if statement.
if(e.getPlayer().isOp()){
List<String> warps = Main.getPlugin().getConfig().getStringList("warplist");
String title = e.getLine(0);
String toWarp = ChatColor.stripColor(e.getLine(1).toLowerCase().trim());
if(title.equalsIgnoreCase("warp")){
if(warps.contains(toWarp)){
e.setLine(0, ChatColor.AQUA + "[Warp]");
e.setLine(1, ChatColor.GREEN + toWarp.substring(0, 1).toUpperCase() + toWarp.substring(1).toLowerCase());
e.getPlayer().sendMessage(ChatColor.GOLD + "Warp Sign Created!");
e.getPlayer().sendMessage(ChatColor.ITALIC + "Plugin Created By Sodex234");
#SuppressWarnings("unchecked")
List<Location> allSigns = (List<Location>) Main.getPlugin().getConfig().getList("signs");
allSigns.add(e.getBlock().getLocation());
Main.getPlugin().getConfig().set("signs", allSigns);
Main.getPlugin().saveConfig();
}else{
e.getPlayer().sendMessage(ChatColor.RED + "That Warp Does Not Exist.");
e.getPlayer().sendMessage(ChatColor.RED + "You put: " + toWarp + ". Only these Warps exist: " + warps);
e.getBlock().setType(Material.AIR);
}
}
}
In game I get the message "That warp does not exist." - and then the List its self. However when it shows me the list, it clearly contains the item.
For instance; the list has 4 items in it, "test", "test2", "test3", "test4". I place down a sign, it knows that it is a warp, and when it comes to checking the name, it returns false? However, the name is "test" and the arraylist contains this. As you can see, I have trimmed it, striped it of chatcolors and put it in lower case (every item in the list is lower case).
The stripping done to the toWarp string doesn't appear to be enough to remove all the characters, leaving some non-renderable characters on the string causing the mismatch.
One thing to do could be to strip all non-alphanumeric characters via some regular expression.
Fixed. It contained non-alphanumeric characters the Minecraft does not support. Used a regex to work this out:
toWarp = toWarp.replaceAll("[^A-Za-z0-9 ]", "");
I need to compare two strings.
The input value is like
SELECT * FROM ds WHERE ds.age='24';
The text against which it needs to be compared being
SELECT * FROM ds WHERE ds.status='VALID' AND ds.age='24';
Since "ds.status='VALID' AND" is a static string, I thought of inserting it into the input and then compare it with the original string.
So I created a StringBuilder object and
query.insert(query.indexOf("WHERE"), "ds.status='VALID' AND");
but the output was
SELECT * FROM ds ds.status='VALID' AND WHERE ds.age='24';
Also, indexOf() cannot be inputted with a static position since it can vary with the input.
Is there any way to find the index of the last letter of the word "WHERE"?
The work-around I found is
String query = query.replace("WHERE", "WHERE ds.status='VALID' AND");
Is this the best possible method?
query.insert(query.indexOf("WHERE") + "WHERE".length(), " ds.status='VALID' AND");
I think the replace is a lot cleaner and easier to read - like Peter Lawrey's comment:
query.replace(" WHERE ", " WHERE ds.status='VALID' AND ");
No having to worry about fencepost errors or magic numbers and so much clearer in intent!
EDIT
That would be:
query.toString().replace(" WHERE ", " WHERE ds.status='VALID' AND ");
(Replace on StringBuilder takes indexes)
You can do something like this -
StringBuffer str = new StringBuffer("SELECT * FROM ds WHERE ds.age='24'");
str.insert(str.lastIndexOf("WHERE") + 6, "ds.status='VALID' AND ");