4

So I'm doing a simple encryption program in Java. The user inputs a string (strTarget), and then that string is taken to this function. In the for-loop, it should take the character's ASCII value, reduce it by 4, and then return it to the string (doing that for all characters in the string). As you see my friends, I have already done that, however, I am not sure on how to reconstruct the string that I wish to get back (e.g. if a user inputs 'efg', the returned string should be 'abc')

So, here's the result I got with the suggestions. I'm obviously doing something wrong in the Menu class, not sure what it is. It stops working when I input a string to be encrypted.

import java.util.Scanner;

public class Menu {

public static String strTarget;

public static void main(String[] args) {


    Scanner in = new Scanner(System.in);

    System.out
            .println("Welcome to the encr/decr program");
    System.out
            .println("To encrypt a string, press 1, to decrypt a string, press 2");
    int choice = in.nextInt();
    if (choice == 1) {
        System.out.println("Type the string you want to encrypt.");
        strTarget = in.next();
        System.out.println(Encrypt(strTarget));
    }
    if (choice == 2) {
        System.out.println("Enter the string you want to decrypt.");
    }

}

private static String Encrypt(String strTarget) {
    // TODO Auto-generated method stub
    int len = strTarget.length()-1;

    String destination = "";

    for (int i = 0; i<len; i++)
    {

        if (strTarget.charAt(i) != ' ')
        {
            char a = strTarget.charAt(i);
            int b = (int) a;
            b = strTarget.charAt(i)-4;
            a = (char) b;
            if ( b<70 && b>64)
            {
                b = strTarget.charAt(i)+26;
                a = (char) b;

                destination += a;
            }
        }


    }
    return destination; 

} }

EDIT: Added the full program.

import java.util.Scanner;

public class Menu {

public static String strTarget;

public static String destination = "";

public static void main(String[] args) {


Scanner in = new Scanner(System.in);

System.out.println("Welcome to the encr/decr program");

System.out.println("To encrypt a string, press 1, to decrypt a string, press 2");



int choice = in.nextInt();

if (choice == 1) {
    System.out.println("Type the string you want to encrypt.");

    strTarget = in.next();

    StringBuilder zomg = new StringBuilder(strTarget);

    System.out.println(Encrypt(zomg));


}

if (choice == 2) {
    System.out.println("Enter the string you want to decrypt.");
}

}

 private static String Encrypt(StringBuilder zomg) {
// TODO Auto-generated method stub

int len = strTarget.length()-1;

for (int i = 0; i<len; i++)
{

    if (strTarget.charAt(i) != ' ')
    {
        char a = strTarget.charAt(i);
        int b = (int) a;
        b = strTarget.charAt(i)-4;
        a = (char) b;
        destination += a;
        if ( b<70 && b>65)
        {
            b = strTarget.charAt(i)+26;
            a = (char) b;
            destination += a;
        }
    }


}
System.out.println(destination);
return destination; 

} }

I made the changes you said (I think), and it start to work, but it isn't working as it is supposed to. Gives some results which do not seem to make sense (for 'A', it return =, for 'V', it returns 'V'). Any suggestions?

speci
  • 147
  • 3
  • 6
  • 13

6 Answers6

2

Just append each converted character to a StringBuilder or StringBuffer.

eboix
  • 5,113
  • 1
  • 27
  • 38
RanRag
  • 48,359
  • 38
  • 114
  • 167
  • 2
    As of release JDK 5, StringBuffer has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization. http://docs.oracle.com/javase/6/docs/api/java/lang/StringBuffer.html – SHiRKiT Jan 08 '12 at 23:53
  • 1
    And for optimal performance, create a stringbuilder with the correct capacity, as you know it beforehand anyway. – Maarten Bodewes Jan 09 '12 at 19:05
2

Here is a recursive solution:

You want to call it with Encrypt(string,0)

private static String Encrypt(String strTarget, int place) {
// TODO Auto-generated method stub
    if (place==strTarget.length()) {
        return strTarget;
    }
    if (strTarget.charAt(place) != ' ')
    {
        char a = strTarget.charAt(place);
        int b = (int) a;
        b = strTarget.charAt(place)-4;
        a = (char) b;
        if ( b<70 && b>64)
        {
            b = strTarget.charAt(place)+26;
            a = (char) b;
        }
        return Encrypt(strTarget.substring(0,place)+a+strTarget.substring(place+1,strTarget.length()),place+1);
    }
    return null;
}
schwert
  • 61
  • 6
0
private static String Encrypt(String strTarget) {
    // TODO Auto-generated method stub
    int len = strTarget.length()-1;

    String destination = "";

    for (int i = 0; i<len; i++)
    {

        if (strTarget.charAt(i) != ' ')
        {
            char a = strTarget.charAt(i);
            int b = (int) a;
            b = strTarget.charAt(i)-4;
            a = (char) b;
            if ( b<70 && b>64)
            {
                b = strTarget.charAt(i)+26;
                a = (char) b;

                destination += a;
            }
        }

    return destination;
    }

I added a new String called destination, added the characters to it, and returned it.

EDIT

However, it seems that you may want to modify the actual String, strTarget.

To do so, you shouldn't pass strTarget as your parameter, because that passes it by value rather than by reference.

To actually modify the String, pass a StringBuilder, as outlined here. (The "here" is a link, by the way.)

EDIT #2

Say you have a method. Call it foo. Foo takes an int as a parameter and sets it to 1:

public static void foo(int i) {
    i = 1;
}

Now you want to test your method:

public static void main(String[] args) {

    int i = 0;
    foo(i);
    System.out.println(i);
}

This should print out 1, right? NO. It doesn't. It prints "0". You can test it, if you want. This is because the integer is "passed by value". When something is passed by value, the virtual machine basically makes a copy of it and passes the copy into the method.

Therefore, when you execute i=1 in your foo method, you are actually setting a copy of i to 1, not i. So i remains unchanged.

There is another type of parameter passing that is called pass by reference. When something is passed by reference, the method modifies the actual variable.

Arrays, for example, are passed by reference. Take this code, for example:

public static void foo(int[] i) {
    i[0] = 1; // i must have at least one element.
}


public static void main(String[] args) {

    int[] i = new int[1];
    foo(i);
    System.out.println(i[0]);
}

In this example, i is modified in foo, as it is passed by reference.

In your original method, you put the return type as void. With the return type as void, you cannot return the encrypted String. So it occurred to me that maybe you wanted to pass by reference and modify strTarget itself.

To do this, instead of passing strTarget, you would pass a StringBuilder. You would create it with new StringBuilder(strTarget) and it would automatically pass by reference. If you wanted this, then what I would do would be to generate the destination String (as outlined above), and then modify the StringBuilder to change strTarget to the destination String.

I hope this helped.

Community
  • 1
  • 1
eboix
  • 5,113
  • 1
  • 27
  • 38
  • That edit gave me a headache, though I believe it will help me eventually. I will try to do some more reading on StringBuilder and how to modify the string, as it is obvious I cannot understand what you are speaking :( – speci Jan 09 '12 at 00:15
  • I updated the code as you said, friend, however it does not return the wanted results :( I guess I'm doing something awfully wrong there.. – speci Jan 09 '12 at 15:13
0

You might want to try something as follows:

private static String encrypt(String strTarget) {
    char[] chars = strTarget.toCharArray();
    for(int i=0; i<chars.length; i++) {
        if(chars[i] != ' ') {
            int asciiVal = chars[i];
            asciiVal -= 4;
            if(asciiVal < 70 && asciiVal > 64) {
                asciiVal += 26;                    
            }
            chars[i] = (char) asciiVal;
        }
    }
    return String.valueOf(chars);
}
Bhesh Gurung
  • 50,430
  • 22
  • 93
  • 142
0

Readable, more object oriented version using some character magic:

private static final int MOD_ALPHABET = 'Z' - 'A' + 1;

private static String rot(int rot, String toEncrypt) {

    int rangedRot = rot % MOD_ALPHABET;
    if (rangedRot < 0) {
        rangedRot = MOD_ALPHABET + rangedRot;
    }

    final StringBuilder sb = new StringBuilder(toEncrypt);
    for (int i = 0; i < sb.length(); i++) {
        final char plainChar = sb.charAt(i);
        final char startChar;
        if (plainChar >= 'A' && plainChar <= 'Z') {
            startChar = 'A';
        } else if (plainChar >= 'a' && plainChar <= 'z') {
            startChar = 'a';
        } else {
            continue;
        }

        char cryptChar = (char) (plainChar - startChar);
        cryptChar += rangedRot;
        cryptChar %= MOD_ALPHABET;
        cryptChar += startChar;
        sb.setCharAt(i, cryptChar);
    }
    return sb.toString();
}
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
-1

Initialize an empty String before the for loop:

String target = "";

In the inner if do this:

target += a;

That shoud do it!

return target;
v01pe
  • 1,096
  • 2
  • 11
  • 19
  • `StringBuilder` should be preferred over this, as this will create numerous objects in memory, and the input is not known in advance. – Maarten Bodewes Jan 09 '12 at 19:08