Decryption code not changing actual data - java

I am having issues running my code correctly. I created a decryption method that is supposed to take a word and replace every 2 letters with each other. Unless the word is an odd amount, then I should leave the last letter alone. The issue is that I am only printing out the letters and not changing the actual data of the string.
static String ezDecrypt (String ezEncrypt){
//this variable holds the value of the String's length
int cl = ezEncrypt() ;
//if the length of the String is even then do this
if (ezEncrypt.length() % 2 == 0){
//for loop that begins at 0
//keeps looping until it reaches the end of the string
//each loop adds 2 to the loop
for(int i = 0; i < cl; i= i + 2) {
//will print out the second letter in the string
System.out.print(ezEncrypt.charAt(i + 1));
//will print out the first letter in the string
System.out.print(ezEncrypt.charAt(i));
}
}
//if the length of the word is an odd number, then
else if(ezEncrypt.length() % 2 != 0){
//loop through and do the same process as above
//except leave this loop will skip the last letter
for(int i = 0; i < cl-1; i= i + 2) {
//will print out the second letter in the string
System.out.print(ezEncrypt.charAt(i + 1));
//will print out the first letter in the string
System.out.print(ezEncrypt.charAt(i));
}
}
return ezEncrypt;
}

I understand you're trying to modify a String in order to decrypt it. Well, I got some news for you: the String class in java has been designed in such a way String objects are immutable. That means you can't alter their contents once you have created them. But don't worry, there are other ways to achieve what you have in mind.
For instance, you can get an array of chars from the received object by calling ezEncrypt.toCharArray(); you can modify the contents of an array so you will have to work with that, swapping the characters just like you're supposed to. Then, once the decryption is done, create another String object by using the constructor new String(char[] chars), passing your array as argument, and return it.
Something more or less like this:
static String ezDecrypt (String ezEncrypt){
//this variable holds the value of the String's length
int cl = ezEncrypt.length();
//an array holding each character of the originally received text
char[] chars = ezEncrypt.toCharArray();
//temporary space for a lonely character
char tempChar;
//Do your swapping here
if (ezEncrypt.length() % 2 == 0){ //Length is even
//for loop that begins at 0
//keeps looping until it reaches the end of the string
//each loop adds 2 to the loop
for(int i = 0; i < cl; i = i + 2) {
tempChar = chars[i];
chars[i] = chars[i+1];
chars[i+1] = tempChar;
}
} else { //Length is odd
//loop through and do the same process as above
//except leave this loop will skip the last letter
for(int i = 0; i < cl - 1; i = i + 2) {
tempChar = chars[i];
chars[i] = chars[i+1];
chars[i+1] = tempChar;
}
}
return new String(chars);
}
Hope this helps you.

Strings are immutable, so calling a method on the string will not change the string. It will only return a value derived from the string. You need to make a new empty string and start adding the return values to it character by character.

Related

Remove a Character From String in Java

I'm trying to concatenate a string with itself and remove all capital letters from the resultant string.
Here is my code:
public String removeCapitals(String A) {
StringBuilder B = new StringBuilder(A+A);
int n = B.length();
for(int i=0; i<n; i++){
if(B.charAt(i)>='A' && B.charAt(i)<='Z'){
B.deleteCharAt(i);
}
}
return B.toString();
}
I'm getting Exception saying:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 6
at java.lang.AbstractStringBuilder.charAt(AbstractStringBuilder.java:237)
at java.lang.StringBuilder.charAt(StringBuilder.java:76)
at Solution.removeCapitals(Solution.java:10)
at Main.main(Main.java:190)
Can someone help me to understand the issue.
If at least one removal succeeds, at some point your code will attempt to access an invalid index that exceeds the length of a StringBuilder.
It happens because the variable n remain unchanged. You should change the condition to be bound to the current size of StringBuilder and decrement the index at each removal, or iterate backwards (as shown in another answer).
Also condition B.charAt(i)>='A' && B.charAt(i)<='Z' can be replaced with:
Character.isUpperCase(b.charAt(i))
Which is more descriptive.
That's how it might look like:
public static String removeCapitals(String a) {
StringBuilder b = new StringBuilder(a + a);
for (int i = 0; i < b.length(); i++) {
if (Character.isUpperCase(b.charAt(i))) {
b.deleteCharAt(i); // which can be combined with the next line `b.deleteCharAt(i--);` - previous value of `i` would be used in the call `deleteCharAt()` and variable `i` will hold a value decremented by 1
i--;
}
}
return b.toString();
}
Method deleteCharAt() runs in a linear time, because it shifts all subsequent characters in the underlying array bytes. Each upper-case letter will trigger these shifts and in the worst case scenario, it would result in the quadratic overall time complexity O(n ^ 2).
You make your method more performant and much more concise without using loops and StringBuilder. This code will run in a linear time O(n).
public static String removeCapitals(String a) {
return a.replaceAll("\\p{Upper}", "").repeat(2);
}
When you delete a character you change the length of the StringBuilder. But n still has the original length. So you will eventually exceed the size of the StringBuilder. So start from the end and move backwards. That way, any deletions will come after (based on relative indices) the next position so the index will be within the modified StringBuilder size. In addition, deleting from the end is more efficient since there is less copying to do in the StringBuilder.
public String removeCapitals(String A) {
StringBuilder B = new StringBuilder(A+A);
int n = B.length();
for(int i=n-1; i>=0; i--){
if(B.charAt(i)>='A' && B.charAt(i)<='Z'){
B.deleteCharAt(i);
}
}
return B.toString();
}
If just remove Capital characters from a string. Alternative solution just create another method replaceAll() + regex
private static String removeCapitals(String A){
if (!A.isEmpty() && !A.equals("")) {
String B = A + A;
String newStr = B.replaceAll("([A-Z])", "");
return newStr;
} else {
return null;
}
}
Shorter solution to your task.
String a = "ABcdEF";
String b = "";
for (int i = 0; i < a.length(); i++) {
if(a.toLowerCase().charAt(i) == a.charAt(i))
b+=a.charAt(i);
}
System.out.println(b);
By changing to .toUpperCase() you'll get rid of the lower case ones.

breaking down any String

Hi guys I am busy with breaking / splitting Strings.
However the String is not fixed so when the input changes the program still has to work with any character input.
Till now I got this far but I got lost.
I have made an array of characters and set the size of the array equal to the lenght of any string that is will get as input. I made a for loop to loop through the characters of a string.
how do I insert my string now into the array because I know that my string is not yet in there? Then when its finally looping through the characters of my string is has to printout numbers and operands on different lines. So the ouput would look like in this case like this;
1
+
3
,
432
.
123
etc
I want to do this without using matchers,scanner, etc. I want to use basic Java techniques like you learn in the first 3 chapters of HeadfirstJava.
public class CharAtExample {
public static void main(String[] args) {
// This is the string we are going to break down
String inputString = "1+3,432.123*4535-24.4";
int stringLength = inputString.length();
char[] destArray = new char[stringLength];{
for (int i=0; i<stringLength; i++);
}
You could use Character.isDigit(char) to distinguish numeric and not numeric chars as actually this is the single criteria to group multiple chars in a same line.
It would give :
public static void main(String[] args) {
String inputString = "1+3,432.123*4535-24.4";
String currentSequence = "";
for (int i = 0; i < inputString.length(); i++) {
char currentChar = inputString.charAt(i);
if (Character.isDigit(currentChar)) {
currentSequence += currentChar;
continue;
}
System.out.println(currentSequence);
System.out.println(currentChar);
currentSequence = "";
}
// print the current sequence that is a number if not printed yet
if (!currentSequence.equals("")) {
System.out.println(currentSequence);
}
}
Character.isDigit() relies on unicode category.
You could code it yourself such as :
if (Character.getType(currentChar) == Character.DECIMAL_DIGIT_NUMBER) {...}
Or you could code it still at a lower level by checking that the int value of the char is included in the range of ASCII decimal values for numbers:
if(currentChar >= 48 && currentChar <= 57 ) {
It outputs what you want :
1
+
3
,
432
.
123
*
4535
-
24
.
4
It's easier than you might think.
First: to get an array with the chars of your string you just use the toCharArray() method that all strings have. ex. myString.toCharArray()
Second: When you see that a character is not a number, you want to move to the next line, print the character and then move to the next line again. The following code does exactly that :
public class JavaApplication255 {
public static void main(String[] args) {
String inputString = "1+3,432.123*4535-24.4";
char[] destArray = inputString.toCharArray();
for (int i = 0 ; i < destArray.length ; i++){
char c = destArray[i];
if (isBreakCharacter(c)){
System.out.println("\n" + c);
} else {
System.out.print(c);
}
}
}
public static boolean isBreakCharacter(char c){
return c == '+' || c == '*' || c == '-' || c == '.' || c == ',' ;
}
char[] charArray = inputString.toCharArray();
Here is a possible solution where we go character by character and either add to an existing string which will be our numbers or it adds the string to the array, clears the current number and then adds the special characters. Finally we loop through the array as many times as we find a number or non-number character. I used the ASCII table to identify a character as a digit, the table will come in handy throughout your programming career. Lastly I changed the array to a String array because a character can't hold a number like "432", only '4' or '3' or '2'.
String inputString = "1+3,432.123*4535-24.4";
int stringLength = inputString.length();
String[] destArray = new String[stringLength];
int destArrayCount = 0;
String currentString = "";
for (int i=0; i<stringLength; i++)
{
//check it's ascii value if its between 0 (48) and 9 (57)
if(inputString.charAt(i) >= 48 && inputString.charAt(i) <= 57 )
{
currentString += inputString.charAt(i);
}
else
{
destArray[destArrayCount++] = currentString;
currentString = "";
//we know we don't have a number at i so its a non-number character, add it
destArray[destArrayCount++] = "" + inputString.charAt(i);
}
}
//add the last remaining number
destArray[destArrayCount++] = currentString;
for(int i = 0; i < destArrayCount; i++)
{
System.out.println("(" + i + "): " + destArray[i]);
}
IMPORTANT - This algorithm will fail if a certain type of String is used. Can you find a String where this algorithm fails? What can you do to to ensure the count is always correct and not sometimes 1 greater than the actual count?

Having trouble with for loops

So, I need to write a program using loops that takes a string and counts what and how many letters appear in that string. (string "better butter" would print "b appears 2 times, e appears 3 times, ' '(space) appears 1 time, and so on). While I understand the idea and concept behind this assignment, actually pulling it off has been rough.
My nested for loop is where the problems are coming from, I assume. What I've written only loops once (i think) and just shows the first character and says there's only one of that character.
Edit: Preferably without using Map or arrays. I'm fine with using them if it's the only way, but they've not been covered in my class so I'm trying to avoid them. Every other similar question to this (that I've found) uses Map or array.
import java.util.Scanner;
class myString{
String s;
myString() {
s = "";
}
void setMyString(String s) {
this.s = s;
}
String getMyString() {
return s;
}
String countChar(String s){
s = s.toUpperCase();
int cnt = 0;
char c = s.charAt(cnt);
for (int i = 0; i <= s.length(); i++)
for (int j = 0; j <= s.length(); j++) //problem child here
c = s.charAt(cnt);
cnt++;
if (cnt == 1)
System.out.println(c+" appears "+cnt+" time in "+s);
else
System.out.println(c+" appears "+cnt+" times in "+s);
return "for"; //this is here to prevent complaint from the below end bracket.
}
}
public class RepeatedCharacters {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s;
System.out.println("Enter a sentence: ");
s = in.nextLine();
myString myS = new myString();
// System.out.println(myS.getMyString());
// System.out.println(myS.countChar());
myS.countChar(s);
}
}
First you will need to scan the entire string and store the
counts of each characters. Later you can just print the counts.
Algorithm 1:
Use a HashMap to store the character as key and its count as value. (If you are new to Java, you might want to read up on
HashMaps.)
Every time you read a character in your for loop, check if it present in the HashMap. If yes, then increment the count by 1. Else
add a new characters to the map with count 1.
Printing:
Just iterate on your HashMap and print out the character and
their respective counts.
Issue with your code: You are trying to print the count as soon as you
read a character. But the character might appear again later in the
string. So you need to keep track of the characters you have already
read.
Algorithm 2:
String countChar(String s){
has_processed = []
for i = 0 to n
cnt = 0
if s.charAt(i) has been processed
continue;
for j = i+1 to n
if (s.charAt(i) == s.charAt(j))
cnt++
add s.charAt(i) to has_processed array
print the count of s.charAt(i)
}
Use a frequency array to get an answer in linear time.
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
String s = "better butter";
int freq[] = new int[26];
int i;
for (i = 0; i < s.length(); i++) {
if (s.charAt(i) >= 'a' && s.charAt(i) <= 'z')
freq[s.charAt(i)-'a']++;
}
for (i = 0; i < freq.length; i++) {
if (freq[i] == 0) continue;
System.out.println((char)(i+'a') + " appears " + freq[i] + " times" );
}
}
}
Ideone Link
Note that this can be expanded to include uppercase letters, but for demonstrative purposes, only lowercase letters are handled in the above code.
EDIT: While the OP did ask if it was possible to do this without an array, I would recommend against such. That solution would have terrible time complexity and repeat character counts (unless an array is used to keep track of seen characters, which is counter to the aim). Thus, the above solution is the best way to do it in a reasonable amount of time (linear) with limited space consumption.
I would do the following. Create a HashMap which keeps track of which unique characters are in the string and the count for each character.
You only need to iterate over the string once, and put each character into the HashMap. if the characer is in the map, icrement the integer count in the map, else add 1 to the map for that character. Print out the map with toString() to get the result. The whole thing can be done in about 4 lines of code.
The only thing being done in your nested for loop with the following
c = s.charAt(cnt)
is setting the c char to the value of the first letter (i.e. index 0 of the string) over and over and over until you've looped through the string n^2 times. In other words, you're not incrementing your cnt counter within the for loops at all.
Suggestion: try to use meaningful names for your variables; it will help you a lot in your career. Also class names should always start with a capital letter.
Although it is not the quickest solution in terms of performance, the most simple solution should be:
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
int count = freq.containsKey(word) ? freq.get(word) : 0;
freq.put(word, count + 1);
Source: Most efficient way to increment a Map value in Java
Please next time use the search function before posting a new question.
Here is my version of countChar(String s)
boolean countChar(String s) {
if(s==null) return false;
s = s.toUpperCase();
//view[x] will means that the characted in position x has been just read
boolean[] view = new boolean[s.length()];
/*
The main idea is:
foreach character c = s.charAt(x) in the string s, I have a boolean value view[x] which say if I have already examinated c.
If c has not been examinated yet, I search for other characters equals to c in the rest of the string.
When I found other characters equals to c, I mark it as view and I increment count with count++.
*/
for (int i = 0; i < s.length(); i++) {
if (!view[i]) {
char tmp = s.charAt(i);
int count = 0;
for (int j = i; j < s.length(); j++) {
if (!view[j] && s.charAt(j) == tmp) {
count++;
view[j] = true;
}
}
System.out.println("There were " + count + " " + tmp);
}
}
return true;
}
It should work, excuse me for my English because I'm italian

Java - Help converting letter to integer, adding 5, then converting back to letter

First off, here is my code so far
public int encrypt() {
/* This method will apply a simple encrypted algorithm to the text.
* Replace each character with the character that is five steps away from
* it in the alphabet. For instance, 'A' becomes 'F', 'Y' becomes '~' and
* so on. Builds a string with these new encrypted values and returns it.
*/
text = toLower;
encrypt = "";
int eNum = 0;
for (int i = 0; i <text.length(); i++) {
c = text.charAt(i);
if ((Character.isLetter(c))) {
eNum = (int) - (int)'a' + 5;
}
}
return eNum;
}
(text is the inputted string by the way. And toLower makes the string all lower case to make it easier converting.)
I got most of my assignment done, but one part of it is tasking me with moving every letter inputted 5 spaces over. A becomes F, B becomes G, etc.
So far from I got the letter converted to a number, but I am having trouble adding to it and then returning it back to a letter.
When I run the program and I enter my input such as "abc" I get '8'. It just adds them all up.
Any help would be much appreciated, and I can post the full code if necessary.
Few issues -
First of all - eNum = (int) - (int)'a' + 5; you do not need the first (int) - i believe, you can just do - eNum = (int)c + 5; . Your expression would always result in a negative integer.
Instead of returning eNum you should convert it to character and add it to a string and return the string at end (or you can create a character array of same length as string , keep storing the characters in the array, and return a string created from the character array).
Instead of using a in the condition , you should use c which denotes the current character at the ith index.
I am guessing not all of the variables in your code are member variables (instance variables) of the class , so you should define them with a datatype in your code.
Example changes to your code -
String text = toLower; //if toLower is not correct, use a correct variable to get the data to encrypt from.
String encrypt = "";
for (int i = 0; i <text.length(); i++) {
char c = text.charAt(i);
if ((Character.isLetter(c))) {
encrypt += (char)((int)c + 5);
}
}
return encrypt;
//Just a quick conversion for testing
String yourInput = "AbC".toLowerCase();
String convertedString = "";
for (int i = 0; i <text.length(); i++) {
char c = yourInput.charAt(i);
int num = Character.getNumericValue(c);
num = (num + 5)%128 //If you somehow manage to pass 127, to prevent errors, start at 0 again using modulus
convertedString += Integer.toString(num);
}
System.out.println(convertedString);
Hope this is what you're looking for.
Try something like this, I believe this has several advantages:
public String encrypt(String in) {
String workingCopy = in.toLowerCase();
StringBuilder out = new StringBuilder();
for (int i = 0; i < workingCopy.length(); i++) {
char c = workingCopy.charAt(i);
if ((Character.isLetter(c))) {
out.append((char)(c + 5));
}
}
return out.toString();
}
This code is a little bit verbose, but perhaps then it is easier to follow. I introduced the StringBuilder because it is more efficient than doing string = string + x

Finding characters in a string

i'm doing an encoding program where i'm supposed to delete every character in the string which appears twice. i've tried to traverse through the string but it hasn't worked. does anyone know how to do this? Thanks.
public static String encodeScrambledAlphabet(String str)
{
String newword = str;
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
newword += alphabet;
newword = newword.toUpperCase();
for (int i = 0, j = newword.length(); i < newword.length() && j >=0; i++,j--)
{
char one = newword.charAt(i);
char two = newword.charAt(j);
if (one == two)
{
newword = newword.replace(one, ' ');
}
}
newword = newword.replaceAll(" ", "");
return newword;
}
Assuming that you would like to keep only the first occurrence of the character, you can do this:
boolean seen[65536];
StringBuilder res = new StringBuilder();
str = str.toUpperCase();
for (char c : str.toCharArray()) {
if (!seen[c]) res.append(c);
seen[c] = true;
}
return res.toString();
The seen array contains flags, one per character, indicating that we've seen this character already. If your characters are all ASCII, you can shrink the seen array to 128.
Assuming by saying deleting characters that appears twice, you mean AAABB becomes AAA, below code should work for you.
static String removeDuplicate(String s) {
StringBuilder newString = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
String s1 = s.substring(i, i + 1);
// We need deep copy of original String.
String s2 = new String(s);
// Difference in size in two Strings gives you the number of
// occurences of that character.
if(s.length() - s2.replaceAll(s1, "").length() != 2)
newString.append(s1);
}
return newString.toString();
}
Efficiency of this code is arguable :) It might be better approach to count the number of occurences of character by a loop.
So, from the code that you've shown, it looks like you aren't comparing every character in the string. You are comparing the first and last, then the second and next to last. Example:
Here's your string:
THISISTHESTRINGSTRINGABCDEFGHIJKLMNOPQRSTUVWXYZ
First iteration, you will be comparing the T at the beginning, and the Z at the end.
Second iteration, you will be comparing the H and the Y.
Third: I and X
etc.
So the T a the beginning never gets compared to the rest of the characters.
I think a better way to do this would be to to do a double for loop:
int length = newword.length(); // This way the number of iterations doesn't change
for(i = 0; i < length; i++){
for(j = 0; j < length; j++){
if(i!=j){
if(newword.charAt(i) == newword.charAt(j)){
newword.replace(newword.charAt(i), ' ');
}
}
}
}
I'm sure that's not the most efficient algorithm for it, but it should get it done.
EDIT: Added an if statement in the middle, to handle i==j case.
EDIT AGAIN: Here's an almost identical post: function to remove duplicate characters in a string

Categories