Java code goes infinite loop when trying to replace certain string - java

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) {
}

Related

What am I missing with this code? Google foo.bar

So recently I got invited to this google foo.bar challenge and I believe the code runs the way it should be. To be precise what I need to find is the number of occurrences of "abc" in a String. When I verify my code with them, I pass 3/10 test cases. I'm starting to feel bad because I don't know what I am doing wrong. I have written the code which I will share with you guys. Also the string needs to be less than 200 characters. When I run this from their website, I pass 3 tests and fail 7. Basically 7 things need to be right.
The actual question:
Write a function called answer(s) that, given a non-empty string less
than 200 characters in length describing the sequence of M&Ms. returns the maximum number of equal parts that can be cut from the cake without leaving any leftovers.
Example : Input : (string) s = "abccbaabccba"
output : (int) 2
Input: (string) s = "abcabcabcabc"
output : (int) 4
public static int answer(String s) {
int counter = 0;
int index;
String findWord ="ABC";
if(s!=null && s.length()<200){
s = s.toUpperCase();
while (s.contains(findWord))
{
index = s.indexOf(findWord);
s = s.substring(index + findWord.length(), s.length());
counter++;
}
}
return counter;
}
I see a couple of things in your code snippet:
1.
if(s.length()<200){
Why are you checking for the length to be lesser than 200? Is that a requirement? If not, you can skip checking the length.
2.
String findWord ="abc";
...
s.contains(findWord)
Can the test program be checking for upper case alphabets? Example: "ABC"? If so, you might need to consider changing your logic for the s.contains() line.
Update:
You should also consider putting a null check for the input string. This will ensure that the test cases will not fail for null inputs.
The logic of your code is well but on the other hand i found that you didn't check for if input string is empty or null.
I belief that google foo.bar wants to see the logic and the way of coding in a proper manner.
so don't be feel bad
I would go for a simpler approach
int beforeLen = s.length ();
String after = s.replace (findWord, "");
int afterLen = after.length ();
return (beforeLen - afterLen) / findWord.length ();
String pattern = "abc";
String line="<input text here>";
int i=0;
Pattern TokenPattern=Pattern.compile(pattern);
if(line!=null){
Matcher m=TokenPattern.matcher(line);
while(m.find()){
i++;
}}
System.out.println("No of occurences : "+ " "+i);
put declaration of index out before while block, isn't never good re-declare the same variable n time.
int index;
while (s.contains(findWord))
{
index = s.indexOf(findWord);
....
}
I hope this help
Update:
try to compact your code
public static int answer(String s) {
int counter = 0;
int index;
String findWord = "ABC";
if (s != null && s.length() < 200) {
s = s.toUpperCase();
while ((index = s.indexOf(findWord)) > -1) {
s = s.substring(index + findWord.length(), s.length());
counter++;
}
}
return counter;
}
Update:
The logic seems good to me, I'm still try to improve the performance, if you can try this
while ((index = s.indexOf(findWord, index)) > -1) {
//s = s.substring(index + findWord.length(), s.length());
index+=findWord.length();
counter++;
}

Reversing the order of a string

So I'm still shaky on how basic java works, and here is a method I wrote but don't fully understand how it works anyone care to explain?
It's supposed to take a value of s in and return it in its reverse order.
Edit: Mainly the for loop is what is confusing me.
So say I input "12345" I would want my output to be "54321"
Public string reverse(String s){
String r = "";
for(int i=0; i<s.length(); i++){
r = s.charAt(i) + r;
}
return r;
}
We do a for loop to the last index of String a , add tha carater of index i to the String s , add here is a concatenation :
Example
String z="hello";
String x="world";
==> x+z="world hello" #different to z+x ="hello world"
for your case :
String s="";
String a="1234";
s=a.charAt(0)+s ==> s= "1" + "" = "1" ( + : concatenation )
s=a.charAt(1)+s ==> s='2'+"1" = "21" ( + : concatenation )
s=a.charAt(2)+s ==> s='3'+"21" = "321" ( + : concatenation )
s=a.charAt(3)+s ==> s='3'+"321" = "4321" ( + : concatenation )
etc..
public String reverse(String s){
String r = ""; //this is the ouput , initialized to " "
for(int i=0; i<s.length(); i++){
r = s.charAt(i) + r; //add to String r , the caracter of index i
}
return r;
}
What this code does is the following
Create a new variable r="";
then looping for the string in input lenght it adds at the beginning of r the current character of the loop.
i=0) r="1"
i=1) r="21"
i=2) r="321"
i=3) r="4321"
i=4) r="54321"
When you enter the loop you are having empty string in r.
Now r=""
In 1st iteration, you are taking first character (i=0) and appending r to it.
r = "1" + "";
Now r=1
In 2nd iteration, you are taking second character (i=1) and appending r to it
r = "2" + "1";
Now r=21
You can trace execution on a paper like this, then you will easily understand what is happening.
What the method is doing is taking the each character from the string s and putting it at the front of the new string r. Renaming the variables may help illustrate this.
public String reverse(String s){
String alreadyReversed = "";
for(int i=0; i<s.length(); i++){
//perform the following until count i is as long as string s
char thisCharacterInTheString = s.charAt(i); // for i==0 returns first
// character in passed String
alreadyReversed = thisCharacterInTheString + alreadyReversed;
}
return alreadyReversed;
}
So in the first iteration of the for loop alreadyReversed equals 1 + itself (an empty string).
In the second iteration alreadyReversed equals 2 + itself (1).
Then 3 + itself (21).
Then 4 + 321.
Then 5 + 4321.
GO back to your problem statement (take an input string and produce an output string in reverse order). Then consider how you would do this (not how to write Java code to do this).
You would probably come up with two alternatives:
Starting at the back of the input string, get one character at a time and form a new string (thus reversing its order).
Starting at the front of the string, get a character. Then for each next character, put it in front of all the characters you have created so far.
Your pseudo code results might be like the following
Option 1
let l = the length of the input string
set the output string to ""
while l > 0
add the "lth" character of the input string to the output string
subtract 1 from l
Option 2 left as an exercise for the questioner.
Then you would consider how to write Java to handle your algorithm. You will find that there are several ways to get the "lth" character of a string. First, in Java a string of length l has characters in position 0 through l-1. You can use string.charAt(loc) or string.substring(loc,loc+1) to get the character at position loc

java: code keeps looping

The below code is giving me a headache: It's supposed to jump out of the do--while loop after replacing all \n's, but it doesn't. Any ideas how to solve this?
public String invoerenTemplate(){
String templateGescheiden = null;
String teHerkennenTemplate = Input.readLine();
String uitvoer = teHerkennenTemplate;
do {
templateGescheiden = teHerkennenTemplate.substring(0, teHerkennenTemplate.indexOf(" "));
templateGescheiden += " ";
if (templateGescheiden.charAt(0) == '\\' && templateGescheiden.charAt(1) == 'n') {
teHerkennenTemplate = teHerkennenTemplate.replace(templateGescheiden, "\n");
uitvoer = uitvoer.replace(templateGescheiden, "\n");
}
teHerkennenTemplate = teHerkennenTemplate.substring(teHerkennenTemplate.indexOf(" "));
System.out.println(uitvoer);
} while (teHerkennenTemplate.length() > 0);
return uitvoer;
}
EDIT:
I now placed this line: teHerkennenTemplate.trim(); just beneath my if-statement, but now it gives me a StringIndexOutOfRange: 0 error at my first line of my if-statement
I have noticed a couple of problems with the above code, although it is difficult to tell why you are taking the approach that you are to the solution.
The main thing I noticed is that your replace statements do NOT remove the \n characters
teHerkennenTemplate = teHerkennenTemplate.replace(templateGescheiden, "\n");
uitvoer = uitvoer.replace(templateGescheiden, "\n");
From Java Documentation:
replace(char oldChar, char newChar):
Returns a new string resulting from replacing all occurrences of oldChar in this string with newChar.
So, you are replacing your string templateGescheiden with \n each time you loop.
Another issue would be the improper shortening of your teHerkennenTemplate string each loop, which is causing it not to terminate correctly. It will always shorten from the next space character to the end of the string (inclusive) - meaning it will never be an empty string, but will always have a " ".
My advice would be to debug and go step-by-step to see where the shortening and string manipulation is not doing what you want, then evaluate why and modify the code appropriately
There's a variety of things wrong with the code:
the index of a carriage return is found in the string with indexOf("\n").
the substring of teHerkennenTemplate isn't taking into account that it starts with a space, which cause the loop to continue forever.
The simplest way to do what you want is with a regular expression:
"test \n test \n".replaceAll("\n", "")
Will return:
"test test "
If you're set on using a loop then this will do the same:
public static String invoerenTemplate(String teHerkennenTemplate)
{
StringBuilder result = new StringBuilder();
while (teHerkennenTemplate.length() > 0)
{
int index = teHerkennenTemplate.indexOf("\n");
result.append(index > -1 ? teHerkennenTemplate.substring(0, index) : teHerkennenTemplate);
teHerkennenTemplate = teHerkennenTemplate.substring(index + 1, teHerkennenTemplate.length());
}
return result.toString();
}

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,"");
}

Returning null with String matching alg

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.

Categories