-1

I'm trying to encrypt and decrypt strings using cipher text with a random keyword. The random keyword will be in a file "keyword.txt":

TROYONLINE

The string(s) will be in a separate file "input.txt":

THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG
more lines here....

The cipher should use the keyword and a reversed alphabet without redundant letters. The cipher for keyword "TROYONLINE" would be:

TROYNLIEZXWVUSQPMKJHGFDCBA

Using this cipher, the above string will be encrypted to this:

HEN MGZOW RKQDS LQC XGUPNY QFNK HEN VTAB YQI

So far, I have this code:

import java.util.*;
import java.io.*;

public class reverseString
{
   public static void main(String [] args)
   {
      String abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
      String cipher = "";
      String newCipher;
      String encrypt = "";
      String ouput = "";

      BufferedReader readerKeyword = null;
      String key = "";
      try 
      {
          readerKeyword = new BufferedReader(new FileReader("keyword.txt"));          
      }
      catch (FileNotFoundException fnfex)
      {
         System.out.println(fnfex.getMessage() + " File not found.");
         System.exit(0); 
      }
      try
      {
         while ((key = readerKeyword.readLine()) !=null)
         {
           StringBuffer sb = new StringBuffer();

         int len = abc.length();

         for(int i = len -1;i>=0;i--)
              cipher = cipher + abc.charAt(i);

         newCipher = sb.append(key).append(cipher).toString();
         System.out.println(key);
         System.out.println(removeDuplicates(newCipher));

         }
      }
      catch (IOException ioex)
      {
         System.out.println(ioex.getMessage() + " Unable to read file.");
         System.exit(0);
      }

       BufferedReader readerInput = null;
        String lineInput;

       try 
       {
              readerInput = new BufferedReader(new FileReader ("input.txt"));           
       }
       catch (FileNotFoundException fnfex)
       {
         System.out.println(fnfex.getMessage() + " File not found.");
         System.exit(0); 
       }
       try
       {
          while ((lineInput = readerInput.readLine()) !=null)
          {
           char[] inputArray = lineInput.toCharArray();
           System.out.println(inputArray);
          }
       }
       catch (IOException ioex)
       {
         System.out.println(ioex.getMessage() + " Unable to read file.");
       }
   }

   static String removeDuplicates(String newCipher)
   {
      char[] charArr = newCipher.toCharArray();
      Set<Character> charSet = new LinkedHashSet<Character>();
      for(char ch : charArr)
      {
         charSet.add(ch);
      }
      StringBuffer StrBuf = new StringBuffer();
      for(char c : charSet)
      {
         StrBuf.append(c);

      }

      char[] cipherArray = removeDuplicates(newCipher).toCharArray();
      System.out.println(cipherArray);
      return StrBuf.toString();
   }
}

But I'm getting the below error:

TROYONLINE
Exception in thread "main" java.lang.StackOverflowError
    at java.util.HashMap.<init>(HashMap.java:456)
    at java.util.LinkedHashMap.<init>(LinkedHashMap.java:347)
    at java.util.HashSet.<init>(HashSet.java:161)
    at java.util.LinkedHashSet.<init>(LinkedHashSet.java:154)
    at reverseString.removeDuplicates(reverseString.java:83)
    at reverseString.removeDuplicates(reverseString.java:94)

With a ton of repeats of the last line ...(reverseString.java:94)

tima
  • 1,498
  • 4
  • 20
  • 28
sfrank
  • 3
  • 1
  • 6
  • 3
    Please don't use StringBuffer, it was replaced by StringBuilder more than 10 years ago. – Peter Lawrey Apr 29 '17 at 20:58
  • thanks for the suggestion, but how can that help with my error? – sfrank Apr 29 '17 at 21:04
  • You've posted way too much code here. (For example: instead of having tons of `try`/`catch` blocks, you should just use `throws Exception`.) In asking a Stack Overflow question, your goal should be to provide **minimal** complete code that demonstrates your problem. Similarly, you should put `{` at the end of the previous line, so that your code requires less scrolling; and you should use consistent whitespace, so that your code is readable. – ruakh Apr 29 '17 at 21:05
  • 2
    Get the spelling of your method name straight. In your post, you have used `removedRedundantLetters` twice and `removeRedundantLetters` twice. (see the extra `d` in front of `Redundant` in the first case). Compilers don't correct spelling mistakes - they just see them as different names (hence "symbol not found") – Erwin Bolwidt Apr 29 '17 at 21:32
  • @ruakh `throws Exception` and `catch (Exception ...)` are bad practice overall. All those `try-catch` blocks throw `IOException`, so that's the one to catch. The difficulty is not in the `throws` clause anyway, but in the organization of the try-catches, and the non-use of try-with-resources. – Lew Bloch Apr 29 '17 at 22:24
  • Whether it helps with your error or not, and the fact that it's a comment not an answer is a big hint there, using `StringBuilder` rather than `StringBuffer` is good advice, and the correct response, @sfrank, is "Thank you!" – Lew Bloch Apr 29 '17 at 22:26
  • @LewBloch: Sorry, I think you've misunderstood something. I'm not making a statement about how the OP should write normal Java code; rather, I'm explaining how the OP should write StackOverflow questions that include Java code. Specifically: (s)he should post **minimal** complete examples. – ruakh Apr 30 '17 at 00:04
  • @ErwinBolwidt I noticed the 'd' and removed from my code right after I posted, but I'm still getting the error. My readln command to read out the new keyword array without duplicate letters should be called from the main method, right? I tried it in the removeRedundantLetters method and it never compiled, like I thought, so I'm sure I have to call it from the main, just figure out how to get it to work. I'll edit my OP to get rid of the extra 'd'. – sfrank Apr 30 '17 at 00:26

2 Answers2

0

EDIT

Belows is how I would do this in your situation. But keep this in mind:

  1. It makes no sense to have your key and the input text in files. If you have a lot of input lines then you would pass the key as a command line argument and have only one while loop that reads the input file and uses the same key to encrypt and decrypt. If you do have multiple keys, then you need to read each key and then read the whole input file line by line, then read the next key and read the input file again, etc., etc.
  2. I have all of the logic in the main method but you should break it down into separate methods.

Main class:

String defaultAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

BufferedReader keyInputLine;
String key;
String cipher = "";
BufferedReader inputLine;
String inputText;
StringBuilder encryptedText;
StringBuilder decryptedText;

try {
    keyInputLine = new BufferedReader(new FileReader("keyword.txt"));
    
    while ((key = keyInputLine.readLine()) != null) {
        System.out.println("key: " + key);
        
        StringBuilder stringBuilder = new StringBuilder();
        
        // cipher is the key word plus the reverse of the alphabet
        cipher = stringBuilder.append(key).append(new StringBuilder(defaultAlphabet).reverse().toString()).toString();
        
        System.out.println("cipher: " + cipher);
        
        // remove duplicates from cipher
        cipher = removeDuplicates(cipher);
        
        System.out.println("replaced cipher: " + cipher);
    }
        
    inputLine = new BufferedReader(new FileReader("input.txt"));
    
    while ((inputText = inputLine.readLine()) != null) {
        System.out.println("original: " + inputText);
        
        encryptedText = new StringBuilder();
        
        for (char c : inputText.toCharArray()) {
            // find the input letter in the alphabet
            if (defaultAlphabet.indexOf(c) != -1) {
                // replace with same index from the cipher
                encryptedText.append(cipher.toCharArray()[defaultAlphabet.indexOf(c)]);
            } else {
                // if not found, use default (ex: space)
                encryptedText.append(c);
            }
        }
        
        System.out.println("encrypted: " + encryptedText.toString());
        
        decryptedText = new StringBuilder();
        
        for (char c : encryptedText.toString().toCharArray()) {
            // find the encrypted letter in the cipher
            if (cipher.indexOf(c) != -1) {
                // replace with same index from the cipher
                decryptedText.append(defaultAlphabet.toCharArray()[cipher.indexOf(c)]);
            } else {
                // if not found, use default (ex: space)
                decryptedText.append(c);
            }
        }
        
        System.out.println("decrypted: " + decryptedText.toString());
    }
} catch (IOException e) {
    e.printStackTrace();
}

The remove duplicates method:

static String removeDuplicates(String cipher) {
    Set<Character> charSet = new LinkedHashSet<Character>();
        
    for (char ch : cipher.toCharArray()) {
        charSet.add(ch);
    }
        
    StringBuilder stringBuilder = new StringBuilder();
        
    for (char c : charSet) {
        stringBuilder.append(c);
    }
        
    return stringBuilder.toString();
}

Previous Answer

It's like the error says, the "lineKeyword" variable is not initialized before being used. Consider that it is possible that there is an exception in your second try/catch. The exception is caught and you print a message but "lineKeyword" is still uninitialized.

There is a good answer here: Uninitialized variables and members in Java

The language defines it this way.

Instance variables of object type default to being initialized to null. Local variables of object type are not initialized by default and it's a compile time error to access an undefined variable.

See section 4.5.5 in here http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html#96595

Community
  • 1
  • 1
tima
  • 1,498
  • 4
  • 20
  • 28
  • I was able to figure it out with help in another thread. I botched this thread up pretty good - my brain is basically fried - so I started over with a better question (prob should have just edited this one, in hindsight) see my answer for the code that solved it. Another question though, I've edited this post to update my issue. – sfrank Apr 30 '17 at 05:48
  • @sfrank What is the error you are getting? From what I see, you have two issues: 1) "cipher" is not declared and 2) "abc" is not declared. Where are you writing this code? The editor should show these as erros even before you compile. You should post the exact copy of what you have, and also it would help if you posted the "keyword.txt" file that you are reading. – tima Apr 30 '17 at 13:02
  • I 've updated the OP in response to your comment. Thanks! – sfrank Apr 30 '17 at 14:16
  • @sfrank Your code works, you don't need the commented out lines. You should just move the `int len = abc.length(); for(int i = len -1;i>=0;i--) cipher = cipher + abc.charAt(i);` out of the while loop since it only needs to run once. This is what I get: `key: TROYONLINE cipher: ZYXWVUTSRQPONMLKJIHGFEDCBA newCipher: TROYONLINEZYXWVUTSRQPONMLKJIHGFEDCBA replaced newCipher: TROYNLIEZXWVUSQPMKJHGFDCBA` – tima Apr 30 '17 at 15:09
  • Also, it is better to use StringBuffer like @PeterLawrey said – tima Apr 30 '17 at 15:13
  • I moved the `int len` part out of the while loop and you were right, it was fine. But then I uncommented ` char[] cipherArray = removeDuplicates(newCipher).toCharArray(); System.out.println(cipherArray); return StrBuf.toString(); ` in the static String removeDuplicates method, but I'm still seeing the `Exception in thread "main" java.lang.StackOverflowError` error. – sfrank Apr 30 '17 at 18:36
  • @sfrank I meant that you don't need those two lines, just remove them – tima Apr 30 '17 at 18:40
  • oh I see, you say I don't need the commented lines at all. But currently it is a string, I'm trying to convert it to a char array. I need to use the contents of the input.txt and the contents of the String newCipher to be char arrays so I can perform a substitution cipher. Is there an easier way to do it with leaving them both as strings? – sfrank Apr 30 '17 at 18:43
  • here is my end goal, just not sure of the best way to do. I thought using char arrays would be best: `***Encryption*** read String lineInput and search for characters: for every 'A' found, replace with string newCipher(pos 0) for every 'B' found, replace with string newCipher(pos 1) and so on until for every 'Z' found, replace with string newCipher(pos 25) Insert each replacement into String encrpyted ***Decryption*** read String encrypted and search for characters: for every 'A' found, replace with string abc(pos 0) Insert each replacement into String encrypted ` – sfrank Apr 30 '17 at 18:53
  • I messed around with so many different idea over the last few days that I lost track of what I had tried and what I hadn't. Eventually, I used logic similar to yours, except I used `stringbuffer int len = abc.length(); for(int i = len -1;i>=0;i--) cipher = cipher + abc.charAt(i); newCipher = sb.append(key).append(cipher).toString();` I've accepted an answer, but there is still the question of replacing characters with a specific index from another string. I went ahead and converted both srings to char Arrays. I still can't figure out the char sub – sfrank May 01 '17 at 14:32
  • @sfrank The code I posted does a replacement of characters with a specific index from another string. You should copy the code into .a new main class, execute it and take a look at the output. Also try to debug it and see how it works, if you need to change it to suit your needs. – tima May 01 '17 at 14:44
0

I ended up putting my cipher code in a the while loop on the BufferedReader code and it cleared it up.

{
      BufferedReader readerKeyword = null;
      String key = "";
      try 
      {
          readerKeyword = new BufferedReader(new FileReader("keyword.txt"));          
      }
      catch (FileNotFoundException fnfex)
      {
         System.out.println(fnfex.getMessage() + " File not found.");
         System.exit(0); 
      }
      try
      {
         while ((key = readerKeyword.readLine()) !=null)
         {
         StringBuffer sb = new StringBuffer();

         int len = abc.length();

         for(int i = len -1;i>=0;i--)
              cipher = cipher + abc.charAt(i);

         newCipher = sb.append(key).append(cipher).toString();
         System.out.println(key);
         System.out.println(removeDuplicates(newCipher));

         }
      }
      catch (IOException ioex)
      {
         System.out.println(ioex.getMessage() + " Unable to read file.");
         System.exit(0);
      }
sfrank
  • 3
  • 1
  • 6