Replacing characters in Strings Java [duplicate] - java

This question already has an answer here:
String Replace not working as I think it should [duplicate]
(1 answer)
Closed 8 years ago.
I need to cycle through each character in a string, and based on the character that it is, replace it with another character from a char array.
Basically it looks like this:
for (int k = 0; k < messageToBeEncrypted.length(); k++)
{
switch(messageToBeEncrypted.charAt(k))
{
case 'a' : messageToBeEncrypted.replace('a', cryptList[0]);
break;
case 'b' : messageToBeEncrypted.replace('b', cryptList[1]);
break;
//it keeps going for each letter of the alphabet
}
System.out.println(messageToBeEncrypted);
}
The char array cryptList is a randomly generated alphabet, "fgtaixnebqwjkzumlydrovsphc" A is to be replaced by f, b by g, and so on. The problem I'm having is that this code prints the exact same message that was inputted, so if the messageToBeEncrypted was ab, instead of fg, it prints ab. How can I fix this? And if theres a clearer more concise way to accomplish this, do tell me. I realize 26 case statements probably isn't the best way to achieve my goal.

If you want to google it the keyword is Substitution cipher.
Here a short help:
String messageToBeEncrypted = "HelloWorld".toLowerCase();
String alphabet = "fgtaixnebqwjkzumlydrovsphcab";
StringBuilder sb = new StringBuilder();
int pos;
for (int k = 0; k < messageToBeEncrypted.length(); k++)
{
pos = (messageToBeEncrypted.charAt(k) - 97);
sb.append(alphabet.charAt(pos));
}
System.out.println(sb.toString());
The number 97 is the offset in the ASCII table... My example is just for small letters, but its not that hard to complete it for every letter.

This seems about what your after (minus the brutal switch statement):
public static String substitutionCipher(String str) {
//i'm assuming that this random alphabet is exactly 26 long, each unique
char[] crypt = "fgtaixnebqwjkzumlydrovsphc".toCharArray();
char[] chars = str.toCharArray();
for(int i = 0; i < chars.length; i++){
chars[i] = crypt[((int) chars[i]) - 97];
}
return new String(chars);
}
But to answer your original question, the reason it's not working is that Strings are immutable. By calling String.replace, it's not modifying your string; that's actually returning the modified version of the string and then just disappearing since you're not storing the return value.
You'd need to say:
for (int k = 0; k < messageToBeEncrypted.length(); k++)
{
switch(messageToBeEncrypted.charAt(k))
{
case 'a' :
messageToBeEncrypted = messageToBeEncrypted.replace('a', cryptList[0]);
break;
case 'b' :
messageToBeEncrypted = messageToBeEncrypted.replace('b', cryptList[1]);
break;
//etc.
}
System.out.println(messageToBeEncrypted);
}
but the way I mentioned previously is a little gentler on memory.

Related

Behavior of foreach when setting new chars in a String

I just read a question about chars and I had a doubt about it so I started to try some code... I'm trying to set all chars from a String one by one using a loop, I've tried with for and the "forEach" version of it, these are my tests:
String testString = "testing";
char[] array = testingString.toCharArray();
Then the loops:
for(int i = 0; i < array.length; i++) {
array[i] = 'x';
}
And this is the output for that loop: (the expected one)
"xxxxxxx"
But then I've tried with the another "for" format:
for(char c: array) {
c = 'x';
}
And it didn't work for me.. the output was the same String ("testing"). I'm misunderstanding the behavior of the for each? Why is the 2nd loop not working the same as the first one? I've used that loop format a lot of times but I can't understand why is not working in this case. I'm not familiar with the char type, maybe I'm missing something about it.
As documented in JLS ยง14.14.2. The enhanced for statement, the following loop:
for(char c: array) {
c = 'x';
}
is equivalent to the following basic for statement:
for (int #i = 0; #i < array.length; #i++) {
char c = array[#i];
c = 'x';
}
As you can see, changing c will not affect the array.
That's because you are edditing the character, not the corresponding charAt the inception String.
Probably, you should take the position of these char at the string and setting it up.

Replace entire char array with different char

I'm very new to programming and I've spent some time looking for a way to do this that I can understand. I'm making a hangman game in java, it's all text based, and I've got almost the entire thing done. All I need is to replace a character array that holds the value of a random word to be replaced with dashes. So if the word was "java" I need to change that character array to "----". Since the word is chosen at random from a list, I have to find a way to use the length of the word to apply those dashes, but I'm not sure how.
Any help is appreciated!
A simple way to replace all the characters by '_' would be :
char[] charArray = {'W','O','R','D'};
Arrays.fill(charArray, '_');
I will give you an example based on what you have provided so far with java and ----:
public class Program {
public static void main(String[] args) {
String value = "java";
char[] array = value.toCharArray();
// Convert string to a char array.
for(int i = 0; i < value.length(); i++)
{
array[i] = '-';
}
// Loop over chars in the array.
for (char c : array) {
System.out.print(c);
}
}
}
OK, a few things that may be helpful in solving this task:
If you have a String you can easily get the length of that String like this:
String word = "java";
int lengthOfWord = word.length();
You can easily edit the contents of an array by accessing the individual elements:
char[] array = new char[4];
array[0] = '-';
array[1] = '_';
array[2] = '-';
array[3] = '_';
If you want to do something repeatedly and know how often you want to do that, using a for-loop is often a great idea. And you can use the counter within the loop. So for example:
int sum = 0;
for(int i = 0; i < 10; i++) {
sum += i;
}
So, combine those pieces of information and you can replace every element of that array. :-)

Counting lower case letters in a string and printing out their occurrence in the form of a histogram?

I am currently trying to write a program where the user will input a string and then the program will output the occurrence of lowercase letters as such:
"Hello world! The quick brown fox jumps over the fence."
a:
b:*
c:**
d:*
e:*****
f:**
g:
h:***
... so on until z.
I just have no idea how to go about writing this. I've looked around but no one uses arrays. I was thinking you have an array for the alphabet and then have a loop that takes each element of the string and corresponds it with a letter of the alphabet, which then adds one to the counter which wil ultimately display the histogram.
Just not sure how to go about it.
Thanks.
EDIT: Here's what I have so far. It's not much and I still don't really understand what to do. But it's something.
import java.util.Scanner;
public class CountingChars {
public static void main(String[] args) {
System.out.println("Enter the text you would like to count the characters of. Please end with a blank line.");
Scanner sc = new Scanner(System.in);
String userInput = sc.nextLine();
String alphabet = "abcdefghijklmnopqrstuvwxyz";
int[] amount = new int[alphabet.length()];
//for (int i = 0; i < userInput.length();i++){
//}
char occurrence;
int count = 0;
while(userInput.length()>0){
occurrence = userInput.charAt(0);
int i = 0;
while(i < userInput.length() && userInput.charAt(i) == occurrence){
count++;
}
}
}
}
Two basic ways of doing this which come to mind.
First is using an array of fixed length with stored ints (lower alph chars), where 'a' is on index 0. And then iterate through the given chararray updating the specific index (you can get the index by something like 'selectedChar' - 'a', which will give you the index position). Then you simply iterate through the list a print number of asterisks accordingly.
Second way is using a HashMap, where you store per each character the value, count the chars, update the value in the map accordingly and then simply go through the map and print those out (now that I am thinking about it, SortedMap will be better).
public static void printAlphabetHistogram(String input) {
int amount[] = new int[25];
for(char c : input.toCharArray()) {
if(Character.isAlphabetic(c)) {
c = Character.toLowerCase(c);
amount[c - 'a'] += 1;
}
}
for(int i = 0; i < amount.length; i++) {
System.out.printf("%s:", (char)('a' + i));
for(int j = 0; j < amount[i]; j++) {
System.out.print("*");
}
System.out.println();
}
}

Avoiding duplicates without Sets?

I am in a beginner Java class and I haven't gotten the chance to learn how to avoid duplicated values when storing values inside arrays.
String[] newAlphabet = new String[26];
for(int I = 0; I < newAlphabet.length; I++){
int random = (65 + (int)(Math.random() * ((90 - 65) + 1));
char ascii = (char)random;
String letters = ascii + "";
if(letters != newAlphabet[0] && letters != newAlphabet[1] ... so on and so on until
newAlphabet[25])
newAlphabet[I] = letters;
}//end
So this is my pseudo code for part of my program and the point of it is to avoid having duplicated letters inside the array.
The problem that I am having is inside the if statement. Instead of typing letters != newAlphabet[] to 25, is there another way of doing it?
I have seen some of the forums in stackedoverflow that I should use HashSet but I have not learned that? I can ask my teacher if I am allowed but is there another way to avoid this problem?
I have been thinking of using for-each loop to search through all the elements in the array but I haven't thought out the plan long enough if it's valid.
As you are talking about a beginner Java class, I am assuming you are fairly new to programming. So, rather than just give you a library function that will do it for you, let's walk through the steps of how to do this with just the basic code so you can get a better idea of what is going on behind the scenes.
Firstly, for any repetitive action, think loops. You want to check, for each letter in your new alphabet, if the one you are about to add matches it. So...
boolean exists = false; //indicates whether we have found a match
for (int j = 0; j < 26; j++) { //for each letter in the new alphabet
//true if this one, or a previous one is a match
exists = exists || letters == newAlphabet[i];
}
//if we don't have a match, add the new letter
if (!exists) newAlphabet[I] = letters;
Now, as you are building up your new alphabet as we go, we don't have a full 26 letters for most cases of running this code, so only check the parts of the new alphabet we have defined:
boolean exists = false;
for (int j = 0; j < I; j++) { //note in this line we stop before the insertion point
exists = exists || letters == newAlphabet[i];
}
if (!exists) newAlphabet[I] = letters;
Finally, we don't need to keep checking if we have already found a match, so we can change the loop to stop when we have found a match:
boolean exists = false;
int j = 0;
while (!exists && j < I) { //we now also stop if we have already found a match
exists = letters == newAlphabet[i];
//as we are stopping at the first match,
//we no longer need to allow for previous matches
}
if (!exists) newAlphabet[I] = letters;
You could use the asList method:
if( Arrays.asList(newAlphabet).contains(letters) ) {
newAlphabet[I] = letters;
}
It's not the most efficient, but since your array is only 26 elements long, I would favor clarity over efficiency.
Some explanation: asList is a static method on the Arrays class. This just means that we don't have to create an Arrays object to call it. We simply say Arrays.asList() and pass it the arguments. The asList method takes an array (newAlhpabet in this case) as a parameter, and builds a java.util.List out of it. This means that we can call List methods on the return value. contains() is a method on List that returns true if the List contains an element that is equal to the parameter (letters in this case).
Based on this line it looks like all you're trying to do is produce the letters A to Z in some other order:
int random = (65 + (int)(Math.random() * ((90 - 65) + 1));
If I'm understanding that right, then really all you're trying to do is shuffle the alphabet:
// Initialize new alphabet array
String originalAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] newAlphabet = originalAlphabet.toCharArray();
// Shuffle the new alphabet by swapping each character to a random position
for (int i=0; i<26; i++) {
int j = (int)(Math.random() * 26);
char temp = newAlphabet[i];
newAlphabet[i] = newAlphabet[j];
newAlphabet[j] = temp;
}
// Print the new alphabet
for (int i=0; i<26; i++) {
System.out.print(newAlphabet[i]);
}
System.out.println();
Here's a sample output: VYMTBIPWHKZNGUCDLRAQFSOEJX
You have a couple options.
Loop through the array and do basically what you're doing now.
Insert the characters in sorted order so you can perform binary search to determine if a letter is already in the list. As a bonus, if you use option 2, you'll already know the insertion point.
Check out Arrays.binarySearch(): http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html
You could use this :
if(Arrays.binarySearch(newAlphabet, letters) < 0){
newAlphabet[I] = letters;
}
You should either include a while loop to make sure each index of the array is filled before moving to the next or you could make use of the return value of Arrays.binarySearch which is (-(insertion index) - 1) to fill the array and exit when the array is filled up.

Scramble a Word using Java

I wanted to scramble a String, to make it unreadable and so came up with this method:
public String scrambleWord(String start_word){
char[] wordarray = start_word.toCharArray();
char[] dummywordarray = start_word.toCharArray();
Random random = new Random();
int r = random.nextInt(wordarray.length-1);
int i = 0;
int j = r+1;
while(i <= r){
dummywordarray[wordarray.length -i-1] = wordarray[i];
i++;
}
while (j <= wordarray.length -1){
dummywordarray[j-r-1] = wordarray[j];
j++;
}
String newword = String.valueOf(dummywa);
return newword;
SO I first converted the string to a char array, and in my method I had to duplicate the char array "dummywordarray". Passing once through this algorithm every lette rof the word will have changed position. But it wont be scrambled very well, in the sense that you could put it back together at a glance.
SO I passed a given String of less than 9 characters through the method 7 times, and the words are fairly well scrambled, i.e. unreadable.
But I tried it with a 30 character string and it took 500 passes before I could guarantee it was nicely scrambled. 500!
I'm sure there is a better algorithm, I'd like some advice on either
a)improving this method
or
b)a better way.
How about
ArrayList<Character> chars = new ArrayList<Character>(word.length());
for ( char c : word.toCharArray() ) {
chars.add(c);
}
Collections.shuffle(chars);
char[] shuffled = new char[chars.size()];
for ( int i = 0; i < shuffled.length; i++ ) {
shuffled[i] = chars.get(i);
}
String shuffledWord = new String(shuffled);
In other words, you could take advantage of the existing java.util.Collections.shuffle(List) method. Unfortunately you have to jump through a couple of hoops to use it, since you can't use primitives in Generics.
Edit:
The basic way that shuffle works (see the Javadoc for the full explanation), is like this:
for position = last_index to first_index
let swap_pos = random number between first_index and position, inclusive
swap(swap_pos, position)
Edit 2:
This approach is significantly less verbose with Guava's Chars utilities:
List<Character> chars = Chars.asList(word.toCharArray());
Collections.shuffle(chars);
String shuffledWord = new String(Chars.toArray(chars));

Categories

Resources