Returning null with String matching alg - java

am implementing a String matching algorithm for a username database. My method takes an existing Username database and a new username that the person wants and it checks to see if the username is taken. if it is taken the method is supposed to return the username with a number that isn't taken in the database.
Example:
"Justin","Justin1", "Justin2", "Justin3"
Enter "Justin"
return: "Justin4" since Justin and Justin with the numbers 1 thru 3 are already taken.
In my code sample below, newMember returns null and I don't know why. It should return "justin4"
public class UserName {
static String newMember(String[] existingNames, String newName){
boolean found = false;
boolean match = false;
String otherName = null;
for(int i = 0; i < existingNames.length;i++){
if(existingNames[i].equals(newName)){
found = true;
break;
}
}
if(found){
for(int x = 1; x < 100 ; x++){
for(int i = 0; i < existingNames.length;i++){
if(existingNames[i].equals(newName + x))
match = true;
}
if(!match)
otherName = newName + x;
}
// It returns NULL instead of "Justin4". Its as if otherName doesn't
// change after its initialization.
return otherName;
} else return newName;
}
public static void main(String[] args){
String[] userNames = new String[4];
userNames[0] = "Justin1";
userNames[1] = "Justin2";
userNames[2] = "Justin3";
userNames[3] = "Justin";
System.out.println( newMember(userNames, "Justin"));
}
}

You need to reset match to false at the start of each x loop iteration. Otherwise, it will match an earlier number, and match will be stuck at true for the rest of the x iterations. You'll never see that it doesn't match for a larger x.
You should also break out of the x loop when you find a name, otherwise you will keep overwriting otherName with a larger x.
You may wish to break out of the i loop (although you don't need to) for efficiency; no sense checking the rest if you already know there's a match.

You're never resetting your match variable. So if it is set to true in the first run, it is never set to false again, and if(!match) otherName = newName + x; never happens. Change this
if(existingNames[i].equals(newName + x))
match = true;
to
match = existingNames[i].equals(newName + x);

I don't know if case sensitivity is also important for you, in which case you should be careful to use equalsIgnoreCase method instead of equals in your case, just for safety. Also if your username database is a SQL database, I suggest doing this check against the database itself with a query, it should be somewhat more efficient.
Otherwise yes, reset your match variable.

You also need to break of the outer for loop in the if(found), once you have the newName, along with resetting the boolean to false.
Or it will just get concatenated to a very long userName.

Related

Java: I compare two Strings but it didn't recognize it

I have this problem:
I wrote this function because I need to get the index of the occurrence of a particular string st in a String array
static public int indicestring(String[] array, String st) {
int ret = -1;
for (int i = 0; i < array.length; i++){
if (st.equals(array[i])) {
ret=i;
break;
}
}
return ret;
}
I then called:
System.out.println("indicestring(NODO,"ET2"));
and I got the correct number.
But then when I do:
String[] arcos2 = linea.split("-");//reading from a file and separating by "-"
String aux = arcos2[1];
System.out.println(arcos2[1]);
System.out.println(aux);
if (aux.equals(arcos2[1])) {
System.out.println("Is equal 1");
}
if (aux.equals("ET2")) {
System.out.println("Is equal 2");
}
if ("ET2".equals(aux)) {
System.out.println("is equal 3");
}
The first two prints were ET2, but then it only printed of the 3 ifs is "Is equal 1".... The thing is I have nearly 200 nodes like "ET2" and only 3 are failing and giving me -1 in the first function...
My question is....Am I using wrong the arrays to save and compare the data, because if aux=arcos2[1]="ET2", why is 'aux.equals("ET2") 'or 'arcos2[1].equals("ET2)' not working
? Is ther another function you can recommend to try?(I tried changing equals with compareTo() == 0 and that didn't work either and trimming was also recommended).
Before, I had a similar error where I compare two arrays like this:
if(a[0] == b[0] && a[1] == b[1])
There was a case that clearly was correct but it was ignored...
But it got corrected when a i changed it to:
if (Arrays.equals(a, b))
Is there maybe some change like that
You should put a debug break point in the code and add expression watches to identify the root cause of the problem.

Java code goes infinite loop when trying to replace certain string

The following code replaces the occurrence of the string in between % %.
String OrgStr = "Alarm for %Received Number% has arrived %test% is ok. Please visit %Received Number%";
String rcNumber = "1234567";
int firstPer, secPer;
do
{
firstPer = OrgStr.indexOf('%'); //position of first %
secPer = OrgStr.indexOf('%', firstPer+1); //position of second %
//extract the string in between first % and second %
String toBeReplac = OrgStr.substring(firstPer, secPer+1);
//The replaced string
//if (toBeReplac.equals("%Received Number%"))// if i put this if condition then code goes to infinite loop
OrgStr=OrgStr.substring(0, firstPer)+ rcNumber +OrgStr.substring((secPer+1),OrgStr.length());
firstPer = OrgStr.indexOf('%', firstPer+1);
}while(firstPer>0);
System.out.println(OrgStr);
As i have mentioned in the above code, when i put the line if (toBeReplac.equals("%Received Number%")) the code goes in the infinite loop. I want to made the replacement only if the string in between % is Received Number.
Basically the problem is that you reinitialize the value of firstPer on each iteration:
firstPer = OrgStr.indexOf('%');
firstPer always has the value of the first occurrence of '%' and that's why you have an endless loop.
So you need to add a second parameter to that call to make sure that the value of firstPer is updated or initialize firstPer somewhere else, just once, and update its value properly.
EDIT
To clarify, you just need to cut the sentence
firstPer = OrgStr.indexOf('%');
and paste it before do. You will then obtain the following output:
Alarm for 1234567 has arrived %test% is ok. Please visit 1234567
I guess that's the output you're looking for.
Try This :
String Str = "Alarm for %Received Number% has arrived %test% is ok. Please visit %Received Number%";
System.out.println(Str.replaceAll("%Received Number%","Java"));
OutPut :
Alarm for AMROOD has arrived %test% is ok. Please visit AMROOD
Correct code would do:
firstPer = OrgStr.indexOf('%'); //position of first %
secPer = OrgStr.indexOf('%', firstPer+1); //position of second %
if (firstPer == -1 || secPer == 0) {
break;
}
(Or invert the condition and place the rest of the loop inside the if.)
One would better use the more efficient pattern replacement with a StringBuffer
public String eval(String s) {
StringBuffer sb = new StringBuffer();
Pattern variablePattern = Pattern.compile("%([\\w ]{0,20})%");
Matcher matcher = variablePattern.matcher(s);
while (matcher.find()) {
String variable = matcher.group(1);
String value = matcher.group(0);
switch (variable) {
case "":
value = "%"; // "%%" becomes a single "%" (self-escaped.
break;
case "Received Number":
value = "123456";
break;
case "test":
value = "...";
break;
default:
throw new IllegalArgumentException("No such variable: " + variable);
}
matcher.appendReplacement(sb, value);
}
matcher.appendTail(sb);
return sb.toString();
}
Here I considered variable names to consist only out word chars or spaces, upto maximal 20 characters. This should help with sole percents in the text. And a percent might be realized by the variable "%%".
If you maintain the variables in a map name-to-value, you would not need a switch statement,
public String eval(String s, Map<String, String> variables) {
}

Is this sending the right value back? Not working in test Java

SO i made a CharSequence[] array with all the two consecutive uppercase letters. Why is this code not returning the correct values?
public static boolean containConsecCaps(String passw)
{
CharSequence[] consec = {"AA","AB","AC","AD","AE","AF", ... "ZZ"};
boolean contain = false;
String pass = passw;
for (int i = 0; i <= 675; i++)
{
contain = pass.contains(consec[i]);
if (contain == true)
break;
}
return contain;
}
and in the main string, this syntax:
while (consec != false)
{
//Consec.setPassword(password.getPassword());
consec = Consec.containConsecCaps(password.getPassword());
if (consec == false)
break;
else
password.setPassword(reader.readLine("Error. Please enter a password with no consecutive letters: "));
}
now everything else in the three classes work. This is the only problem and it seems to get stuck in the else. Why is it not testing all of the array char's then returning true or not?
It gets stuck in a loop if i enter: AApassword.1 , which fits all the other criteria, except the two consecutive capitals. So then i enter: aApassword.1 , which should fit ALL of the criteria, but it still prints out the else statement, instead of breaking the while loop.
Can anyone help me?

Java codingbat help - withoutString

I'm using codingbat.com to get some java practice in. One of the String problems, 'withoutString' is as follows:
Given two strings, base and remove, return a version of the base string where all instances of the remove string have been removed (not case sensitive).
You may assume that the remove string is length 1 or more. Remove only non-overlapping instances, so with "xxx" removing "xx" leaves "x".
This problem can be found at: http://codingbat.com/prob/p192570
As you can see from the the dropbox-linked screenshot below, all of the runs pass except for three and a final one called "other tests." The thing is, even though they are marked as incorrect, my output matches exactly the expected output for the correct answer.
Here's a screenshot of my output:
And here's the code I'm using:
public String withoutString(String base, String remove) {
String result = "";
int i = 0;
for(; i < base.length()-remove.length();){
if(!(base.substring(i,i+remove.length()).equalsIgnoreCase(remove))){
result = result + base.substring(i,i+1);
i++;
}
else{
i = i + remove.length();
}
if(result.startsWith(" ")) result = result.substring(1);
if(result.endsWith(" ") && base.substring(i,i+1).equals(" ")) result = result.substring(0,result.length()-1);
}
if(base.length()-i <= remove.length() && !(base.substring(i).equalsIgnoreCase(remove))){
result = result + base.substring(i);
}
return result;
}
Your solution IS failing AND there is a display bug in coding bat.
The correct output should be:
withoutString("This is a FISH", "IS") -> "Th a FH"
Yours is:
withoutString("This is a FISH", "IS") -> "Th a FH"
Yours fails because it is removing spaces, but also, coding bat does not display the correct expected and run output string due to HTML removing extra spaces.
This recursive solution passes all tests:
public String withoutString(String base, String remove) {
int remIdx = base.toLowerCase().indexOf(remove.toLowerCase());
if (remIdx == -1)
return base;
return base.substring(0, remIdx ) +
withoutString(base.substring(remIdx + remove.length()) , remove);
}
Here is an example of an optimal iterative solution. It has more code than the recursive solution but is faster since far fewer function calls are made.
public String withoutString(String base, String remove) {
int remIdx = 0;
int remLen = remove.length();
remove = remove.toLowerCase();
while (true) {
remIdx = base.toLowerCase().indexOf(remove);
if (remIdx == -1)
break;
base = base.substring(0, remIdx) + base.substring(remIdx + remLen);
}
return base;
}
I just ran your code in an IDE. It compiles correctly and matches all tests shown on codingbat. There must be some bug with codingbat's test cases.
If you are curious, this problem can be solved with a single line of code:
public String withoutString(String base, String remove) {
return base.replaceAll("(?i)" + remove, ""); //String#replaceAll(String, String) with case insensitive regex.
}
Regex explaination:
The first argument taken by String#replaceAll(String, String) is what is known as a Regular Expression or "regex" for short.
Regex is a powerful tool to perform pattern matching within Strings. In this case, the regular expression being used is (assuming that remove is equal to IS):
(?i)IS
This particular expression has two parts: (?i) and IS.
IS matches the string "IS" exactly, nothing more, nothing less.
(?i) is simply a flag to tell the regex engine to ignore case.
With (?i)IS, all of: IS, Is, iS and is will be matched.
As an addition, this is (almost) equivalent to the regular expressions: (IS|Is|iS|is), (I|i)(S|s) and [Ii][Ss].
EDIT
Turns out that your output is not correct and is failing as expected. See: dansalmo's answer.
public String withoutString(String base, String remove) {
String temp = base.replaceAll(remove, "");
String temp2 = temp.replaceAll(remove.toLowerCase(), "");
return temp2.replaceAll(remove.toUpperCase(), "");
}
Please find below my solution
public String withoutString(String base, String remove) {
final int rLen=remove.length();
final int bLen=base.length();
String op="";
for(int i = 0; i < bLen;)
{
if(!(i + rLen > bLen) && base.substring(i, i + rLen).equalsIgnoreCase(remove))
{
i +=rLen;
continue;
}
op += base.substring(i, i + 1);
i++;
}
return op;
}
Something things go really weird on codingBat this is just one of them.
I am adding to a previous solution, but using a StringBuilder for better practice. Most credit goes to Anirudh.
public String withoutString(String base, String remove) {
//create a constant integer the size of remove.length();
final int rLen=remove.length();
//create a constant integer the size of base.length();
final int bLen=base.length();
//Create an empty string;
StringBuilder op = new StringBuilder();
//Create the for loop.
for(int i = 0; i < bLen;)
{
//if the remove string lenght we are looking for is not less than the base length
// and the base substring equals the remove string.
if(!(i + rLen > bLen) && base.substring(i, i + rLen).equalsIgnoreCase(remove))
{
//Increment by the remove length, and skip adding it to the string.
i +=rLen;
continue;
}
//else, we add the character at i to the string builder.
op.append(base.charAt(i));
//and increment by one.
i++;
}
//We return the string.
return op.toString();
}
Taylor's solution is the most efficient one, however I have another solution that is a naive one and it works.
public String withoutString(String base, String remove) {
String returnString = base;
while(returnString.toLowerCase().indexOf(remove.toLowerCase())!=-1){
int start = returnString.toLowerCase().indexOf(remove.toLowerCase());
int end = remove.length();
returnString = returnString.substring(0, start) + returnString.substring(start+end);
}
return returnString;
}
#Daemon
your code works. Thanks for the regex explanation. Though dansalmo pointed out that codingbat is displaying the intended output incorrectly, I through in some extra lines to your code to unnecessarily account for the double spaces with the following:
public String withoutString(String base, String remove){
String result = base.replaceAll("(?i)" + remove, "");
for(int i = 0; i < result.length()-1;){
if(result.substring(i,i+2).equals(" ")){
result = result.replace(result.substring(i,i+2), " ");
}
else i++;
}
if(result.startsWith(" ")) result = result.substring(1);
return result;
}
public String withoutString(String base, String remove){
return base.replace(remove,"");
}

Search array for value containing all characters(in any order) and return value

I've searched high and low and finally have to ask.
I have an array containing, for example, ["123456","132457", "468591", ... ].
I have a string with a value of "46891".
How do I search through the array and find the object that contains all the characters from my string value? For example the object with "468591" contains all the digits from my string value even though it's not an exact match because there's an added "5" between the "8" and "9".
My initial thought was to split the string into its own array of numbers (i.e. ["4","6","8","9","1"] ), then to search through the array for objects containing the number, to create a new array from it, and to keep whittling it down until I have just one remaining.
Since this is likely a learning assignment, I'll give you an idea instead of an implementation.
Start by defining a function that takes two strings, and returns true if the first one contains all characters of the second in any order, and false otherwise. It should looks like this:
boolean containsAllCharsInAnyOrder(String str, String chars) {
...
}
Inside the function set up a loop that picks characters ch from the chars string one by one, and then uses str.indexOf(ch) to see if the character is present in the string. If the index is non-negative, continue; otherwise, return false.
If the loop finishes without returning, you know that all characters from chars are present in src, so you can return true.
With this function in hand, set up another loop in your main function to go through elements of the array, and call containsAllCharsInAnyOrder on each one in turn.
I think you can use sets for this.
List<String> result = new ArrayList<>();
Set<String> chars = new HashSet<>(Arrays.asList(str.split(""));
for(String string : stringList) {
Set<String> stringListChars = new HashSet<>(Arrays.asList(string.split(""));
if(chars.containsAll(stringListChars)) {
result.add(string);
}
}
There is a caveat here; it doesn't work as you would expect for repeated characters and you haven't specified how you want to handle that (for example, 1154 compared against 154 will be considered a positive match). If you do want to take into account repeated characters and you want to make sure that they exist in the other string, you can use a List instead of a Set:
List<String> result = new ArrayList<>();
List<String> chars = Arrays.asList(str.split(""));
for(String string : stringList) {
List<String> stringListChars = Arrays.asList(string.split("");
if(chars.containsAll(stringListChars)) {
result.add(string);
}
}
Your initial idea was good start, so what you can do is to create not an array but set, then using Guava Sets#powerSet method to create all possible subsets filter only those that have "46891".length mebers, convert each set into String and look those strings in the original array :)
You could do this with the ArrayList containsAll method along with asList:
ArrayList<Character> lookingForChars = new ArrayList<Character>(Arrays.asList(lookingForString.toCharArray()));
for (String toSearchString : array) {
ArrayList<Character> toSearchChars = new ArrayList<Character>(Arrays.asList(toSearchString.toCharArray));
if (toSearchChars.containsAll(lookingForChars)) {
System.out.println("Match Found!");
}
}
You can use String#chartAt() in a nested for loop to compare your string with each of the array's elements.
This method would help you check whether a character is contained in both strings.
This is more tricky then a straigt-forward solution.
The are better algorithms but here one easy to implement and understand.
Ways of solving:
Go through every char at your given string and check if it at the
given arrray.
Collect list for every string from the selected
array containing the given char.
Check if no other char to check.
If there is, Perform A again but on the collected list(result list).
Else, Return all possible matches.
try this
public static void main(String args[]) {
String[] array = {"123456", "132457", "468591"};
String search = "46891";
for (String element : array) {
boolean isPresent = true;
for (int index = 0; index < search.length(); index++) {
if(element.indexOf(search.charAt(index)) == -1){
isPresent = false;
break;
}
}
if(isPresent)
System.out.println("Element "+ element + " Contains Serach String");
else
System.out.println("Element "+ element + " Does not Contains Serach String");
}
}
This sorts the char[]'s of the search string and the and the string to search on. Pretty sure (?) this is O(n logn) vs O(n^2) without sorting.
private static boolean contains(String searchMe, String searchOn){
char[] sm = searchMe.toCharArray();
Arrays.sort(sm);
char[] so = searchOn.toCharArray();
Arrays.sort(so);
boolean found = false;
for(int i = 0; i<so.length; i++){
found = false; // necessary to reset 'found' on subsequent searches
for(int j=0; j<sm.length; j++){
if(sm[j] == so[i]){
// Match! Break to the next char of the search string.
found = true;
break;
}else if(sm[j] > so[i]){ // No need to continue because they are sorted.
break;
}
}
if(!found){
// We can quit here because the arrays are sorted.
// I know if I did not find a match of the current character
// for so in sm, then no other characters will match because they are
// sorted.
break;
}
}
return found;
}
public static void main(String[] args0){
String value = "12345";
String[] testValues = { "34523452346", "1112", "1122009988776655443322",
"54321","7172839405","9495929193"};
System.out.println("\n Search where order does not matter.");
for(String s : testValues){
System.out.println(" Does " + s + " contain " + value + "? " + contains(s , value));
}
}
And the results
Search where order does not matter.
Does 34523452346 contain 12345? false
Does 1112 contain 12345? false
Does 1122009988776655443322 contain 12345? true
Does 54321 contain 12345? true
Does 7172839405 contain 12345? true
Does 9495929193 contain 12345? true

Categories