I have to write a program to censor a string. Whenever I run the program, it works fine the first time, then stops progressing the second time after entering the bad word. I don't get what the problem is. PLease help:

 java.util.Scanner;
public class stringCensorRunner {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
       Scanner input = new Scanner(System.in);
       int menuChoice = 1;

       stringCensor theCensor = new stringCensor();  // a new stringCensor is constructed
       String censored = "";                         // censored is initialized to a null string
       System.out.print("Enter your string: ");      // user prompted to enter the string
       String whatTheUserPut = input.nextLine();
       theCensor.userString(whatTheUserPut);

       //System.out.println("\nThe string is: " + whatTheUserPut);
       //System.out.println("This string has " + theCensor.length() + " characters");

     while (menuChoice != 2)
     {
       if (menuChoice == 1)
       {
       System.out.println("\nThe string is: " + whatTheUserPut);
       // the user enters the bad word
       System.out.print("Enter the bad word: ");  
       String theWord = input.nextLine();
       theCensor.bannedWord(theWord);

       // the length of the bad word is computed
       int lengthOfBadWord = theWord.length();
       String banned = "";

       // a loop to print the required number of stars
       // to cover up the bad word
       for(int i = 1; i <= lengthOfBadWord; i++)
       {
            banned = banned + "*";
       } 
      //    System.out.println("\nbefore while statement");

    // the bad word is replaced with stars  
    while (whatTheUserPut.indexOf(theWord) >= 0)
    {
         int aBegin = 0;
         // if int aEnd is put outside, then the word not found function would work
         int aEnd = whatTheUserPut.indexOf(theWord);
         int bBegin = aEnd + lengthOfBadWord;
         int bEnd = theCensor.length();

        // the program would quit if aEnd < 0
        if(aEnd < 0)
        {
            System.out.println("The word \"" + theWord + "\" was not found");
                    break;
        }

        // the program would compute the string replacing the bad word
        else if (aEnd >= 0)
        {
            String aString = whatTheUserPut.substring(aBegin, aEnd);
            String bString = whatTheUserPut.substring(bBegin, bEnd);
            censored = (aString + banned + bString); 
            whatTheUserPut = censored;
        }

        else
            System.out.println("just something");
    }

        System.out.println("The censored string is: " + censored);

       }

        else if (menuChoice == 2)
        {
            System.out.println("You have chosen 2, program terminating");   
        }

        else 
        {
            System.out.println("Invalid option");
        }

        System.out.print("Enter 1 to continue, 2 to quit: ");
        menuChoice = input.nextInt();
        System.out.println("You chose " + menuChoice);

     }

    }
}

A sample run is as below:
Enter your string: jjjk

The string is: jjjk
Enter the bad word: k
The censored string is: jjj*
Enter 1 to continue, 2 to quit: 1
You chose 1

The string is: jjj*
Enter the bad word: j

It no longer proceeds after the second entry

stringCensor theCensor = new stringCensor(); // a new stringCensor is constructed
String censored = ""; // censored is initialized to a null string
System.out.print("Enter your string: "); // user prompted to enter the string
String whatTheUserPut = input.nextLine();
theCensor.userString(whatTheUserPut);

You need to put that entire section of your code into the while loop. Otherwise none of that stuff gets reset once you continue your program, does it?

I put it in it and this is what it gives me:

Enter your string: i am not happy of this

The string is: i am not happy of this
Enter the bad word: o
The censored string is: i am n*t happy *f this
Enter 1 to continue, 2 to quit: 1
You chose 1
Enter your string:
The string is:
Enter the bad word: p
The censored string is:
Enter 1 to continue, 2 to quit:

I don't want to reset the string
I just want to keep working with the first one i enter

Then you would not need to re-prompt the user for a new String, but you would need to do anything necessary to clear your stringCensor Object (such as clearing the old 'badWord' and reprompting for a new 'badWord' and telling stringCensor about the new one).

I don't really get that

what I thought was that, by replacing the bad word everywhere it occurs in the string(this is what it does), theWord is automatically set to the second word we want to replace by *.

It appears I was confused by your code then. Its really late and I'm still sick but I'll take a look at it for you tomorrow if you'll post all of your classes and methods. I can't do too much without getting an overall picture since I don't immediately see the problem.

ok thanks. Here is the class with the methods

public class stringCensor {
	
	// Declare all the variables going to be needed
    
    private String x, y, userInput, bannedWord, numberOfLettersInbannedword, substring;
    private int aSubstring, beginIndex, censored; 
	
	// a new stringCensor is constructed
	public stringCensor()
	{
		String x, y, userInput;
	}
	
	// the string the user enters is declared
	public void userString(String x)
	{
		userInput = x;
	}
	
	// the method which computes the length of what the user entered 
	public int length()
	{
		int number = userInput.length();
		return number;
	}
	
	// the method to get the starting and ending characters of the bad word
	public String substring(int beginIndex, int endIndex)
	{
		return substring;
	}
	
	// the method to return the index of the first occurence of the word to 
	// be banned starting from aSubstring
	public int indexOf(int aSubstring)
	{
		return aSubstring;
	}
	
	// the method to return the index of the first occurence of the word to 
	// be banned starting from beginIndex
/*	public int indexOf(int aSubstring, int beginIndex)
	{
		return beginIndex;	
	}*/
	
	// the method which sets the bad word
	public void bannedWord(String theBannedWord)
	{
		bannedWord = theBannedWord;
	}
	
}

Ok, so I'm going to explain a bunch of things to you while I go through your code - some of them do not make your code "wrong", but they make it harder to understand and harder to debug. So don't take offense, some of this might seem nitpicky, but it would be stupid of me to help you and not point out everything I notice along the way.

1. Your variable named "whatTheUserPut" is not descriptive and doesn't tell anyone anything about the variable itself. For example, a better variable name would be uncensoredString, since it is the String before it gets censored.
2. Class names, by convention, never start with a lowercase letter. A lot of professors will take off points for not following convention. A good class name would be StringCensor. It makes it easier to identify that your class name represents an Object, among other things. Btw, the convention is simply that class names are camel case, so I might name my class KylesSuperDuperUtility but never kylesSuperDuperUtility or KylesSuperDuperutility etc.
3. You declared a bunch of variables in the StringCensor class that you never use. For example, you never used these: x, y, bannedWord, numberOfLettersInBannedWord, aSubstring, beginIndex, or censored. That indicates that you don't understand how those variables work, so I'll clear it up for you:

[These are your variable declarations at the top of the StringCensor class]

private String x, y, userInput, bannedWord, numberOfLettersInbannedword, substring;

[This is your method]

public void userString(String x)
	{
		userInput = x;
	}

In the above method, the x you are referring to in " = x" is not the same x that you declared at the top of the StringCensor class. The x it is referring to is a completely different x, which exists only because you declared your header as "public void userString(String x)". It has nothing to do with the 'x' that you declared at the top of your class, which you never used (and which you don't need). Basically, the idea is that if you declare a variable at the top of your class, (like you did with userInput, bannedWord, etc) it can be used anywhere in your class. However if you create a method like userString that you did above, whatever "parameters" you put (the stuff like String x, int y, etc, that goes in the method header) can only be used inside of that method. If you have any follow up questions about this or anything, feel free to ask. (You might want to look into what "this." notation means in Java).

Ok so follow me through a test run of your program.

[Starts]
Enter your string: kyle
The string is: kyle
Enter the bad word: y
The censored string is: k*le
Enter 1 to continue, 2 to quit: 1
You chose 1
The string is: k*le
Enter the bad word: 
[Stops]

Right away the first thing I noticed is that your uncensored String, "kyle", did not get reset properly after the first time through the loop. If it had gotten reset properly, it would not have said "the string is k*le". . it would have gone back to saying "the string is kyle". On that note, one of the major problem areas in your program is your inconsistent use of the StringCensor class. For example, you create a String censor and pass in the variables, but you never seem to actually use the methods in the class to do anything. An example of this is how you call theCensor.bannedWord() yet you have a bannedWord variable that you never use (it is declared as 'private', so you can't access it without a getter, and you have no getter, and you don't use it anywhere else in your class either). This is an important flaw because you could have been using the StringCensor class to keep track of your censored word, to keep track of your uncensored word, and to make sure that your censored word never got overwritten with *'s without getting reset back to normal later.


I changed your program so that it makes use of the StringCensor class. For example, instead of always using the 'censored' variable in your other class, it calls getCensored and setCensored, and it also calls getUncensored and setUncensored, and it calls reset, etc. Reset being a method that I created to "reset" your uncensoredWord back to its original state (before it had * in it). All that needed to be done to do that was to initially store two versions of the uncensoredWord. Then, once the one version got * put in it, set firstVersion = duplicateVersion so it'd be back to normal.

Anyway, one of the other major problems that was preventing you from even continuing your program was the same mistake I've pointed out to a couple others yesterday - after you read in an integer with Scanner, such as scanner.nextInt(), it leaves a '\n' in the input stream (from the user hitting enter -- they initially entered both an integer AND they hit enter), so you need to use scanner.nextLine() to get rid of that '\n' (from hitting enter), otherwise your program will fail later.

However, your program also had a lot of other problems - for example, you wanted to use the same uncensored word over and over again, and pick new letters to get *'d out, but when you were setting characters in the String to "*", you were changing the original String itself -- so the next time through the loop, "kyle" would have been "k*le" -- you never set it back to "kyle" like you should have. Etc.


Anyway, although I have the completed program on my computer, it is against daniweb rules to do people's work for them, so I am going to give you some updates to your code that will help you finish your assignment, but I am not going to give you the completed code. Give me a few minutes to decide how to best do that (without being confusing) and I'll post the code.

public class StringCensor {
	
	// Declare all the variables going to be needed
    
    private String duplicateUncensoredWord, uncensoredWord, substring;
	private String bannedWord;
	
	// a new stringCensor is constructed
	public StringCensor()
	{
	}
	
	public String getUncensoredWord(){
		//get the uncensoredWord
	}
	
	public void setUncensoredString(String s){
		//set the uncensored string
	}
	
	public void reset(){
		//reset the uncensoredWord that you modified before so that it is the original version again. 
	}
	
	// the string the user enters is declared
	public void userString(String x)
	{
		//Modify this method so that the uncensoredString (x) is saved in TWO places.
		//Hint: I already declared a new String variable in your class that you can use to do this.
		uncensoredWord = x;
	}
	
	// the method which computes the length of what the user entered 
	public int length()
	{
		int number = uncensoredWord.length();
		return number;
	}
	
	// the method to get the starting and ending characters of the bad word
	public String substring(int beginIndex, int endIndex)
	{
		return substring;
	}
	
	// the method to return the index of the first occurence of the word to 
	// be banned starting from aSubstring
	public int indexOf(int aSubstring)
	{
		return aSubstring;
	}
	
	// the method to return the index of the first occurence of the word to 
	// be banned starting from beginIndex
/*	public int indexOf(int aSubstring, int beginIndex)
	{
		return beginIndex;	
	}*/
	
	// the method which sets the bad word
	public void bannedWord(String theBannedWord)
	{
		 bannedWord = theBannedWord;
	}
	
}

Ok, so I left four methods unimplemented in your StringCensor class. Once you implement them, your program will work. If you read my post carefully, and you read the comments in the methods carefully, and you understand both, you will be able to write the appropriate code pretty easily. Your other class, StringRunner or whatever you called it, is completely implemented and will work as soon as you correctly implement the methods in StringCensor.

import java.util.Scanner;
public class StringCensorRunner {

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int menuChoice = 1;

StringCensor theCensor = new StringCensor(); 
String censored = "";
System.out.print("Enter your string: "); 
String uncensoredString = input.nextLine();
theCensor.userString(uncensoredString);

while (menuChoice != 2)
{
	if (menuChoice == 1)
	{
		
		//Pay special attention here. Originally, your code said "+ uncensoredString". 
		//However, since uncensoredString gets changed to a censored String later in this while
		//loop (i.e. kyle gets changed to k*le), you cannot continue to use the same variable
		// over and over again in later iterations of the while loop. (An iteration
		// just means the next time the loop starts). If you DO reuse the same variable,
		// then its going to say k*le next time, so clearly, that is a problem. The way to fix it 
		// is to have your StringCensor class keep track of your original, unmodified uncensoredString.
		// Therefore, if you have TWO copies of uncensoredString in your StringCensor class,
		// and you only ever modify one of those copies, you will always have one original copy. 
		// Then, at the end of the while loop, you can "reset" the uncensoredString variable by setting
		// the modified copy = the unmodified copy. 
		System.out.println("\nThe string is: " + theCensor.getUncensoredWord());
		System.out.print("Enter the bad word: ");
		String censoredWord = input.nextLine();
		theCensor.bannedWord(censoredWord);

		int lengthOfBadWord = censoredWord.length();
		String banned = "";

		for(int i = 1; i <= lengthOfBadWord; i++)
		{
			banned = banned + "*";
		}

		while (theCensor.getUncensoredWord().indexOf(censoredWord) >= 0)
		{
			int aBegin = 0;
			// if int aEnd is put outside, then the word not found function would work
			int aEnd = theCensor.getUncensoredWord().indexOf(censoredWord);
			int bBegin = aEnd + lengthOfBadWord;
			int bEnd = theCensor.length();

			// the program would quit if aEnd < 0
			if(aEnd < 0)
			{
				System.out.println("The word \"" + censoredWord + "\" was not found");
				break;
			}

			// the program would compute the string replacing the bad word
			else if (aEnd >= 0)
			{
				String aString = theCensor.getUncensoredWord().substring(aBegin, aEnd);
				String bString = theCensor.getUncensoredWord().substring(bBegin, bEnd);
				censored = (aString + banned + bString);
				theCensor.setUncensoredString(censored);
			}

			else
				System.out.println("just something");
		}

		System.out.println("The censored string is: " + censored);

	}

	else if (menuChoice == 2)
	{
		System.out.println("You have chosen 2, program terminating");
	}

	else
	{
		System.out.println("Invalid option");
	}

	System.out.print("Enter 1 to continue, 2 to quit: ");
	menuChoice = input.nextInt();
	String tossAwayTheSlashN = input.nextLine(); // You HAVE to do this otherwise from when
	//the user hit the 'enter' key, it is still in your input stream. 
	System.out.println("You chose " + menuChoice);
	theCensor.reset();
	}

}
}

I thank really really much! I like it when people correct me spotting out all my mistakes b/c from there, I learn much more than when i am told of my small mistakes. I just have a request that may be you might find silly. I can't do much about it b/c i am new in java and i am kind of a slow learner. Could you clarify the getUncensoredWord, setUncensoredString, and the reset methods. I don't get them that much. And i don't know how they would relate to the Runner class.
I am sorry for my disturbances.

I thank really really much! I like it when people correct me spotting out all my mistakes b/c from there, I learn much more than when i am told of my small mistakes. I just have a request that may be you might find silly. I can't do much about it b/c i am new in java and i am kind of a slow learner. Could you clarify the getUncensoredWord, setUncensoredString, and the reset methods. I don't get them that much. And i don't know how they would relate to the Runner class.
I am sorry for my disturbances.

The purpose of the "setUncensoredString" method is so that you can store your uncensored word in a StringCensor Object by calling theCensor.setUncensoredString(theUncensoredString). The purpose of "getUncensoredString" method is so that you can later retrieve your uncensoredString -- so the getUncensoredString method is supposed to return your uncensored String. That way, even though you declared your variable as "private", you can still figure out what its value is by calling getUncensoredString.

The way that those two methods relate to the Runner class is that they allow you to put your Uncensored String in the StringCensor class, which helps you keep track of the String, set the String, get the String, and whatever other methods that you define in the StringCensor class.

Now, the reason you needed a "reset" method was because in your Runner class, you were asking the user for the uncensored String, but then you were overwriting it later. For example, you'd save the uncensored String in a variable, but then later, you'd go through, putting "*'s" in that variable. That strategy didn't allow you to "remember" what your original uncensored String was. So by putting the uncensored String into your StringCensor class, and saving two copies of the uncensored String to begin with, we can then call the reset method to get back the original uncensored String. So if you look at the StringCensor class you'll see there is a duplicateString variable - that is for storing a second copy of the uncensored String when it gets set.

But this strategy isn't necessarily the best - another strategy would be for you to never modify the "uncensored String" at all. Instead, you could make a second String variable and perform the edits on that one. (Again, remember that the original problem was that you wanted to keep censoring the original string in the while loop, but you couldn't do so because you had already edited it)

Thank you for the explanation. Everything is clearer now. I have filled in all the methods and I my program runs almost perfectly. The only problem remaining now is that when I enter a word or letter not found in my string, it does not return me the message it is supposed to from the code below:

#
// the program would quit if aEnd < 0
#
if(aEnd < 0)
#
{
#
System.out.println("The word \"" + censoredWord + "\" was not found");
#
break;
#
}

But still, thanks a lot.

So i need to change my indexOf method, right?

Well, you can use that method if you're only going to allow the user to enter one character, but you cannot if you're going to allow the user to enter Strings.

http://java.sun.com/javase/6/docs/api/java/lang/String.html#replace%28java.lang.CharSequence,%20java.lang.CharSequence%29

You need to look into some of the 'replace' or 'replaceAll' methods, I think. The replace method that takes two CharSequences might work, but I've never used it. But once you look at that, you're going to be confused with how you should create a CharSequence - consider the fact that String implements CharSequence, so you can probably use that method by passing in two Strings as paramaters.

ok thanks. I would see what I can do. Thanks again!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.