I am trying to achieve the result in which if the user enters the word, in plural or singular, the regex should return true
For example 'I want to by drone' or 'I want to by drones'.
#Test
public void testProductSearchRegexp() {
String regexp = "(?i).*?\\b%s\\b.*?";
String query = "I want the drone with FLIR Duo";
String data1 = "drone";
String data2 = "FLIR Duo";
String data3 = "FLIR";
String data4 = "drones";
boolean isData1 = query.matches(String.format(regexp, data1));
boolean isData2 = query.matches(String.format(regexp, data2));
boolean isData3 = query.matches(String.format(regexp, data3));
boolean isData4 = query.matches(String.format(regexp, data4));
assertTrue(isData1);
assertTrue(isData2);
assertTrue(isData3);
assertTrue(isData4);//Test fails here (obviously)
}
Your valuable time on this question is very appreciated.
English is a language with many exceptions. Checking whether a word ends in 's' is simply not sufficient to determine whether it's plural.
The best way to solve this problem is to not solve this problem. It's been done before. Take advantage of that. One solution would be to make use of a third party API. The OED have one, for example.
If you were to make a request to their API such as:
/entries/en/mice
You would get back a JSON response containing:
"crossReferenceMarkers": [
"plural form of mouse"
],
from there it should be easy to parse. Simply checking for the presence of the word 'plural' may be sufficient.
They even have working Java examples that you can copy and paste.
An advantage of this approach is there's no compile-time dependency. A disadvantage is that you're relying on being able to make HTTP requests. Another is that you're limited by any restrictions they impose. The OED allows up to 3k requests/month and 60 requests/minute on their free plan, which seems pretty reasonable to me.
Well something like this is very hard to achieve without external sources. Sure many words in plural end with 's' but there are also a lot of exceptions to this like "knife" and "knives" or "cactus" and "cacti". For that you could use a Map to sort these out.
public static String getPlural(String singular){
String plural;
HashMap<String,String> irregularPlurals = new HashMap<>();
irregularPlurals.put("cactus","cacti");
irregularPlurals.put("knife","knives");
irregularPlurals.put("man","men");
/*add all your irregular ones*/
plural = irregularPlurals.get(singular);
if (plural == null){
return singular + "s";
}else{
return plural;
}
}
Very simple and not very practical but gets the job done when you only have a few words.
Related
I'm brand new to Java. I've been assigned a test and I'm stuck on how to complete it. So the case is like so -
Create a method that returns a patterned string from range A000 to ZZZZ. Parameter for the method is string itself, so if we pass A000 it should return A001, if we pass A001 it should return A002 and so on... A009... A999... AA00... AA99... AB00... AB01... AB99... AC00... to AZZZ.
I've been able to increment the numbers, but am unable to change them to letters when they reach 99. Let's say I input AZ99; it should return AZA0, but I don't know how I should write that logic.
I thought of using arrays, but then I'd have to save each iteration of the pattern in the array, and that seems unfeasible. Then I thought I'd use if...else and write the instances where the numbers should increment into letters, but that's unnecessarily long too. I know this can be done by proper logic, but it fails me. I've scrounged multiple threads on stackoverflow, but I can't find one quite like this one.
This is what I've got so far -
public class StringSeries {
public static String returnString (String inputString) {
String newString = inputString.substring(0,2);
String completeNewString = newString +
(Integer.parseInt(inputString.substring(1,inputString.length()))+1);
System.out.println(completeNewString);
return completeNewString;
}
public static void main (String[] args){
Scanner sc = new Scanner();
String inputString = sc.nextLine();
returnString(inputString);
sc.close();
}
}
I need suggestions on how to do this. Also, please elaborate on how a certain logic would work.
Thanks!
P.S. I've looked a lot for this type of question on forums, and haven't been able to find any. I also realize that this question may be repetitive for non-newbies. I request that you don't be rude and point out similar threads if you know where they are. Thanks.
This is much easier than it seems. All you need to do is convert the string to a number in base 36 (Integer.valueOf, Integer.parseUnsignedInt), add one to it, and convert it to an upper case base-36 string (Integer.toString plus converting that to upper case).
Given array of strings like [“crane", "drain", "refrain”] and a pattern such as *an* where * can match any number of characters.
Return the matching word in an efficient manner. (In this example, "crane")
I can solve it in very simple way:
String [] array = {"crane", "drain", "refrain"};
String pattern="an";
for(String s:array){
if(s.contains(pattern)){
System.out.println(s);
}
}
Is there a way to optimize the code performance in java? Consider array can contains a large number of strings.
You could try it with Regular Expressions (regex).
public class RegexExample3{
public static void main(String args[]){
String [] array = {"crane", "drain", "refrain"};
for(String s:array){
if(java.util.regex.Pattern.matches(".*an.*", s))
System.out.println(""+s);
}
}
}
Here is the link if someone doesn't know about regex and would want to understand it.
well, if you want to check if a word is match a pattern without using any Regex, contains..etc
i suggest to encode the pattern in way that if you encode a word will have same hashing...
but, in your case i suggest to do this:
static String EncodeString(String x){
String output="";
for(int i=0;i<x.length();i++){
// *an* == 0110
char c=x.charAt(i);
if(c=='n'|| c=='a'){
output +="1";
} else {
output +="0";
}
}
return output;
}public static void main(String args[])
{
String pattern="*an*";
String enPattern=EncodeString(pattern);
String word="xyanxvsdanfgh";
String enWord=EncodeString(word);
System.out.println(enPattern+" "+enWord);
int v1=Integer.parseInt(enPattern);
int v2=Integer.parseInt(enWord);
System.out.println(" % :"+ v2%v1);// notice here if word not match the pattern then the MOD operation will NOT return 0
}
The assignment asks for a return of the matching word, so the assumptions are, that there is one word, and only one word matching.
And if there is just one word, it is efficient to return early, instead of looping on. You have been close.
String matching (String pattern, String [] array) {
for (String s:array)
if (s.contains (pattern))
return s;
return "";
}
Think about alternatives, how to measure s.contains (pattern) against Regex.pattern.matches, how many cases you would have to generate, to find a difference. Without doing the measurement, you're not sure, that it isn't less efficient. Maybe the pattern should be precompiled?
In such assignments, supposed you cited it carefully, you usually have to take everything very carefully.
Often people have good ideas about a topic, and can't hesitate to implement their first idea to it. Don't do it!
Given array of strings like [“crane", "drain", "refrain”] and a
pattern such as an where * can match any number of characters.
Return the matching word in an efficient manner. (In this example,
"crane")
Be very sensible for every violation of your expectation. It is asked for returning the matching word. Did you notice the singular case? What might it mean in the context of efficient manner?
Of course you have to know your teacher, whether he is a bit sloppy or not and fluent in the language, he uses. But interfaces of methods which fit together are a big issue in software development and reading the specs carefully, too. You soon end up investing much time into a solution which works, but doesn't fit the problem.
Returning an empty String is probably not the best idea, but seems sufficient for the level, and without further context it is hard to decide, what an appropriate reaction would be, if nothing is found. Again, the wording suggests, that there is exactly one solution.
If I have a parent string (let's call it output) that contains a list of variable assignments like so ...
status.availability-state available
status.enabled-state enabled
status.status-reason The pool is available
And I want to extract the values of each variable in that list given the variable names, ie the substring after the space following status.availability-state, status.enabled-state, and status.status-reason, such that I end up with three different variable assignments making each of the following String comparisons true ...
String availability = output.substring(TODO);
String enabled = output.substring(TODO);
String reason = output.substring(TODO);
availability.equals("available");
enabled.equals("enabled");
reason.equals("The pool is available");
What is the simplest way to do this? Should I even use substring for this?
This is a little tricky because you need to assign the value to a specific variable - you can't just have a map of keys to variables in Java.
I would consider doing this with a switch:
for (String line : output.split('\n')) {
String[] frags = line.split(' ', 2); // Split the line in 2 at the space.
switch (frags[0]) { // This is the "key" of the variable.
case "status.availability-state":
availability = frags[1]; // This assigns the "value" to the relevant variable.
break;
case "status.enabled-state":
enabled = frags[1];
break;
// ... etc
}
}
It's not very pretty, but you don't have too many options.
There seem to be two questions here -- how to parse the string, and how to assign to variables by name.
Tackle the string parsing one step at a time:
first write a program to read one line at a time and output each one in the body of a loop. String.split() or StringTokenizer are two options here.
next enhance this by writing a method to handle one line. The same tools are helpful here, to split on spaces.
You should now have a program that can print name: status.availability-state, value: available for each line of input.
Next, you're asking to programatically assign to variables based on the name of the parameter.
There is no legitimate way to look at a variable's name at runtime (OK, Java 8 reflection has ways, but it shouldn't be used without very good reason).
So, the best you can do is to use a switch or if statement:
switch(name) {
case status.availability-state:
availability = value;
break;
... etc.
}
However, whenever you use switch or if you should think about whether there's a better way.
Is there any reason you can't turn these variables into Map entries?
configMap.add(name,value);
Then to read it:
doSomethingWith(configMap.get("status.availability");
That's what maps are for. Use them.
This is a similar situation to the rookie mistake of using variables called person1, person2, person3... instead of using an array. Eventually they ask "How do I go from the number 25 to my variable person25?" -- and the answer is, you can't, but an array or list makes it easy. people[number] or people.get(number)
A valid alternative is to split the string by \n and add to a Map. Example:
String properties = "status.availability-state available\nstatus.enabled-state enabled\nstatus.status-reason The pool is available";
Map<String, String> map = Arrays.stream(properties.split("\n"))
.collect(Collectors.toMap(s -> s.split(" ")[0], s -> s.split(" ", 2)[1]));
System.out.println(map.get("status.status-reason"));
Should output The pool is available
This loop will match and extract the variables, and you can then assign them as you see fit:
Pattern regex = Pattern.compile("status\\.(.*?)-.*? ([a-z]+)");
Matcher matcher = regex.matcher(output);
while (matcher.find()) {
System.out.println(matcher.group(1) + "=" + matcher.group(2));
}
status\\. matches "status."
(.*?) matches any sequence of characters but isn't greedy, and captures them
-.* matches dash, any chars, space
([a-z]+) matches any string of lower-case letters, and captures them
Here's one way to do it:
Map<String, String> properties = getProperties(propertiesString);
availability = properties.get("availability-state");
enabled = properties.get("enabled-state");
reason = properties.get("status-reason");
// ...
public void getProperties(String input) {
Map<String, String> properties = new HashMap<>();
String[] lines = output.split("\n");
for (String line : lines) {
String[] parts = line.split(" ");
int keyStartIndex = parts[0].indexOf(".") + 1;
int spaceIndex = parts[1].indexOf(" ");
string key = parts[0].substring(keyStartIndex, spaceIndex);
properties.put(key, parts[1]);
}
return properties;
}
This seems to be a bit more straight-forward, in terms of the code that's setting these values, as each value is set to exactly the value from the map, rather than iterating over some list of strings and seeing if it contains a particular value and doing different things based on that.
This is designed with the primary use-case being that the string is created at runtime in memory. If the properties are created in an external file, this code would still work (after creating the desired String in memory), but it may be a better idea to use either a Properties file, or perhaps a Scanner.
I have a situation in a free-text file, where between any pair of two string matches of my choice - e.g.
<hello> and </hello>
I want to replace the occurrence of a third string-match with a different string e.g. '=' with '&EQ;'
e.g.
hi=I want this equals sign to stay the same,but=<hello>
<I want="this one in the hello tag to be replaced"/>
</hello>,and=of course this one outside the tag to stay the same
becomes
hi=I want this equals sign to stay the same,but=<hello>
<I want&EQ;"this one in the hello tag to be replaced"/>
</hello>,and=of course this one outside the tag to stay the same
Basically this is because an XML body is being sent in a value-pair and it is royally screwing things up (I am sent this format by a venue and don't have control over it
My immediate approach was to start with a BufferedReader and parse into a StringBuilder going through line by line using String.indexOf( ) to toggle on and off whether we are in tags or not, but 20 minutes in to this approach it occurred to me this may be a bit brute-force and there might be an existing solution to this kind of problem
I know this approach will work eventually but my question is, is there a better way (that is one that is higher level and uses existing Java libraries / common frameworks e.g. Apache Commons, etc. which would make it less error-prone and more maintainable. I.e. is there a more intelligent way of solving this problem than the approach I am taking? Which is effectively brute-force parsing.
If you want to escape XML, have a look at Apache Commons Lang StringEscapeUtils, specifically StringEscapeUtils.escapeXML, it should do what you need.
My great impenetrable solution is as follows, and it seems to work.
I do apologise that it's so hard to follow but it basically came down to this from factorising and re-factorising, many times over combining similar pieces of code.
It will replace all the occurences of String 'replace' with String 'with' between tokens of 'openToken' and 'closeToken' and should be started with mode=false to begin with
As with most things in life, there's probably a really clever succinct way to do this with RegEx
boolean mode=false
StringBuilder output
while( String line = newLine ) {
mode = bodge( "<hello>", "</hello>", "=", "&EQ;", output, mode );
}
private static boolean bodge( String openToken, String closeToken, String replace, String with, String line, StringBuilder out, boolean mode ) {
String comparator = mode ? closeToken : openToken;
int index = line.indexOf( comparator );
// drop through straight if nothing interesting
if( index == -1 ) {
String outLine = mode ?
replacer( line , replace, with ) :
line;
out.append( outLine );
out.append( "\r\n" );
return mode;
}
else {
int endOfToken = index + comparator.length();
String outLine = line.substring(0, endOfToken);
outLine = mode ?
replacer( outLine , replace, with ) :
outLine;
out.append(outLine );
return bodge( openToken, closeToken, replace, with, line.substring( endOfToken ), out, !mode );
}
}
So this part of the homework wants us to take a Set of Strings and we will return a List of Strings. In the String Set we will have email addresses ie myname#uark.edu. We are to pull the first part of the email address; the name and put it in the String List.From the above example myname would be put into the List.
The code I currently have uses an iterator to pull a string from the Set. I then use the String.contains("#") as an error check to make sure the String has an # symbol in it. I then start at the end of the string and use the string.charAt("#") to check each char. Once It's found i then make a substring with the correct part and send it to the List.
My problem is i wanted to use something recursive and cut down on operations. I was thinking of something that would divide the string.length()/2 and then use String.contains("#") on the second half first. If that half does contain the # symbol then it would call the functions recursively agin. If the back half did not contain the # symbol then the front half would have it and we would call the function recursively sending it.
So my problem is when I call the function recursively and send it the "substring" once I find the # symbol I will only have the index of the substring and not the index of the original string. Any ideas on how to keep track of it or maybe a command/method I should be looking at. Below is my original code. Any advice welcome.
public static List<String> parseEmail(Set<String> emails)
{
List<String> _names = new LinkedList<String>();
Iterator<String> eMailIt=emails.iterator();
while(eMailIt.hasNext())
{
String address=new String(eMailIt.next());
boolean check=true;
if(address.contains("#"))//if else will catch addresses that do not contain '#' .
{
String _address="";
for(int i=address.length(); i>0 && check; i--)
{
if('#'==address.charAt(i-1))
{
_address=new String(address.substring(0,i-1));
check=false;
}
}
_names.add(_address);
//System.out.println(_address);//fill in with correct sub string
}
else
{
//System.out.println("Invalid address");
_names.add("Invalid address");//This is whats shownn when you have an address that does not have an # in it.
} // could have it insert some other char i.e. *%# s.t. if you use the returned list it can skip over invalid emails
}
return _names;
}
**It was suggested I use the String.indexOf("#") BUT according to the API this method only gives back the first occurrence of the symbol and I have to work on the assumption that there could be multiple "#" in the address and I have to use the last one. Thank you for the suggestion though. Am looking at the other suggestion and will report back.
***So there is a string.lastindexOf() and that was what I needed.
public static List<String> parseEmail(Set<String> emails)
{
List<String> _names = new LinkedList<String>();
Iterator<String> eMailIt=emails.iterator();
while(eMailIt.hasNext())
{
String address=new String(eMailIt.next());
if(address.contains("#"))//if else will catch addresses that do not contain '#' .
{
int endex=address.lastIndexOf('#');
_names.add(address.substring(0,endex-1));
// System.out.println(address.substring(0,endex));
}
else
{
// System.out.println("Invalid address");
_names.add("Invalid address");//This is whats shownn when you have an address that does not have an # in it.
} // could have it insert some other char i.e. *%# s.t. if you use the returned list it can skip over invalid emails
}
return _names;
}
Don't reinvent the wheel (unless you were asked too of course). Java already has a built-in function for what you are attempting String.indexOf(String str). Use it.
final String email = "someone#example.com";
final int atIndex = email.lastIndexOf("#");
if(atIndex != -1) {
final String name = email.substring(0, atIndex);
}
I agree to the previous two answers, if you are allowed to use the built-in functions split or indexOf then you should. However if it is part of your homework to find the substrings yourself you should definitely just go through the string's characters and stop when you found the # aka linear search.
You should definitely not under no circumstances try to do this recursively: The idea of divide and conquer should not be abused in a situation where there is nothing to gain: Recursion means function-call overhead and doing this recursively would only have a chance of being faster than a simple linear search if the sub-strings were searched in-parallel; and even then: the synchronization overhead would kill the speedup for all but the most gigantic strings.
Unless recursion is specified in the homework, you would be best served by looking into String.split. It will split the String into a String array (if you specify it to be around '#'), and you can access both halves of the e-mail address.