Java text "encryptor" program problem

Asked

Viewed 1,581 times

4

So, guys, I’m having a little problem with one of the work exercises that I have to do.

The teacher provided a .doc with the instructions for a "Cryptographer" that you should apply a mask to the alphabet and encrypt a text (Enigma style). See the exercise statement:

Your program must have a method to encrypt and decrypt a document.

In both methods, the text file must be loaded and the key (integer value from 2 to 5) requested from the user.

Let’s imagine that each letter has an integer value. We start with the letter A, that holds value 0. Next B worthwhile 1, C with the value 2 and so on to the letter Z.

See the table below:

A   B   C   D   E   F   G   H   I   J   K   L   M   N   O   P   Q   R   S   T   U   V   W   X   Y   Z

0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25

When we encrypt a document we will do the following:

We convert the letter we want to encrypt, putting in its place and letter that is in its position + key.

For example:

We want to convert the lyrics B. Let’s assume that the key entered by the user is 3.

B is in the position 1. The position of B + the key results in 4. Soon, we will replace the letter B, by the letter E.

If the word is BANANA, using the key 3, she will be converted to EDQDQD.

If the value obtained by the sum of position and key is greater than 25 (letter Z), then it should continue at the beginning of the alphabet.

For example: We want to convert the lyrics X. Let’s assume that the key entered by the user is 5.

X is in the position 23. The position of X + the key results in 28. If we go back to the beginning of the alphabet, the number 28 will fall to the letter C. Soon, we will replace the letter X, by the letter C.

If the word is XUXU, using the key 5, she will be converted to CZCZ. In addition white spaces must be converted to a sharp (#). When decrypting, we will do the reverse process."

I’ve done most of the code, but some problems arise: in the output text, instead of appearing "#" he breaks a line between words.

If you have any questions regarding the clarity of my explanation of the problem, please comment.

Follows the code:

import java.util.Scanner;
import java.io.File;
import java.io.PrintWriter;
import java.io.IOException;
public class trab3{

public static void main(String [] args){
    inicio();
}

public static void inicio(){
    try{
        Scanner in = new Scanner(System.in); 

        System.out.println("\finforme o nomedoarquivo.txt:");
        String arquivo = in.nextLine();
// o arquivo de entrada deve estar previamente colocado na pasta do projeto

        File arquivoDeEntrada = new File(arquivo);
        Scanner entrada = new Scanner(arquivoDeEntrada); 

        System.out.println("informe o nomedoarquivodesaida.txt:");
        String arquivosaida = in.nextLine();
// para selecionar o nome do arquivo de saida

        PrintWriter saida = new PrintWriter(arquivosaida); 

        int op = 0;
        int chave;
        do{
            System.out.println("Digite 1 para criptografar o arquivo");
            System.out.println("Digite 2 para descriptografar o arquivo");
            op = in.nextInt();
            if(op != 1 && op != 2){
                System.out.println("Opção inválida.");
                inicio();
            } else {
                System.out.println("informe a chave de 1 até 5");
                chave = in.nextInt();
                if(chave != 1 && chave != 2 && chave != 3 && chave != 4 && chave != 5){
                System.out.println("Chave inválida");
                inicio();
                }
                leituraEscritaDosArquivos(entrada, saida, op, chave);
            }
        } while (op != 1 && op != 2);            
    } catch(IOException e){
        System.out.println("Erro com o arquivo. Tente novamente");
        inicio();
    }
} 

public static void leituraEscritaDosArquivos(Scanner entrada,  PrintWriter saida, int op, int chave){

    while(entrada.hasNext()){  
        String palavra = entrada.next().toUpperCase();

        String resultado = "";
        int key = chave;
        if(op == 1){
            resultado = criptografa(palavra, key);
        }
        else{
            resultado = descriptografa(palavra, key);
        }

        saida.println(resultado);

    }
    saida.close();
    entrada.close();
    System.out.println("Saída gerada com sucesso.");
}

public static String criptografa(String palavra, int chave){    
    String alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    String resultado = "";
    for(int i = 0; i < palavra.length(); i++){
        if(palavra.indexOf(palavra.charAt(i)) == ' '){
            char novaletra = '#';
            resultado = resultado + novaletra;
        }else{
            int posicaodaletra = alfabeto.indexOf(palavra.charAt(i));
            int novaposicao = posicaodaletra + chave;
            if(novaposicao > 25){
                char novaletra = alfabeto.charAt(posicaodaletra+chave-26);
                resultado = resultado + novaletra;
            }else{
                char novaletra = alfabeto.charAt(novaposicao);
                resultado = resultado + novaletra;
            }

        }
    }
    return resultado;
}

public static String descriptografa(String palavra , int chave){    
    String alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    String resultado = "";
    for(int i = 0; i < palavra.length(); i++){
        if(palavra.indexOf(palavra.charAt(i)) == ' '){
            char novaletra = '#';
            resultado = resultado + novaletra;
        }else{
            int posicaodaletra = alfabeto.indexOf(palavra.charAt(i));
            int novaposicao = posicaodaletra - chave;
            if(novaposicao < 0){
                char novaletra = alfabeto.charAt(posicaodaletra-chave+26);
                resultado = resultado + novaletra;
            }else{
                char novaletra = alfabeto.charAt(novaposicao);
                resultado = resultado + novaletra;
            }

        }
    }
    return resultado;
}
}
  • See if the problem is time to save the file or its encryption, make it appear on the console before saving and see where the problem is.

1 answer

2

Your problem is that you are using the Scanner to read the file, not a simple BufferedReader or similar. The Scanner breaks the input into words, so that:

  1. There will never be a blank space, because the Scanner does not return them (upon finding one, he returns the word he has just read, and upon calling next it starts reading a new word);
  2. You’re making a println after converting each word, which introduces a break line enters them.

When doing any reversible file content conversion, it is important to preserve all information so that I do not recommend using Scanner. I suggest replacing:

File arquivoDeEntrada = new File(arquivo);
Scanner entrada = new Scanner(arquivoDeEntrada);

for:

File arquivoDeEntrada = new File(arquivo);
BufferedReader entrada = new BufferedReader(new FileReader(arquivo));

(Note: in this case it can, because the file is ASCII - in practice, also take into account the character encoding - encoding - of the archive)

And, although it is not ideal (for the purpose of this exercise I believe to be ok), replace the reading of several "words" by reading entire lines of the file:

while(entrada.hasNext()){  
    String palavra = entrada.next().toUpperCase();
    ...
    saida.println(resultado);
}

for

for ( String linha = entrada.readLine() ; linha != null ; linha = entrada.readLine() ) {
    palavra = linha.toUpperCase();
    ...
    saida.println(resultado);
}

That solves your line breaking problem. Detail: I don’t know if it was an error when transcribing, but when you check by "invalid key" the keys of the if are closing in the wrong place:

if(chave != 1 && chave != 2 && chave != 3 && chave != 4 && chave != 5){
System.out.println("Chave inválida");
inicio(); // chama inicio() se a chave for inválida?!
}         // e NÃO CHAMA se a chave for válida?!!!
leituraEscritaDosArquivos(entrada, saida, op, chave);

Always look for ident your code correctly, it makes it easy to realize errors of this type.

Commentary

  1. Why do you test for all the values of 1 to 5 to the key? Wouldn’t it be simpler to do:

    if ( chave < 1 || 5 < chave ){
        System.out.println("Chave inválida");
    
  2. This algorithm (Cipher of Caesar) basically makes the sum/subtraction module 26. The "module", as you must have studied in mathematics, is basically the rest of the division, which in Java can be done through the operator %:

    int resto = 12 % 5; // 2
    

    It has a boring detail that are the negative numbers (Java chose to make the result sign the same dividend sign). To get around it, just add 26 when making the subtraction, it is ensured that the result will always be positive:

    // criprografa
    int novaposicao = (posicaodaletra + chave) % 26;
    
    // descriptografa
    int novaposicao = (posicaodaletra - chave + 26) % 26;
    

    The result will be guaranteed (assuming the letter read is not invalid, type one Ç) a number between 0 and 25, eliminating the need for that if.

  3. In practice, multiple string concatenations can cause performance problems, as a new string is created with each operation (since strings are immutable). For this exercise I believe it is not necessary, but get used to using a StringBuilder whenever you need to do several successive operations with string:

    // Em vez de:
    String s = "";
    s += str1;
    s += str2;
    s += str3;
    
    // Faça:
    StringBuilder sb = new StringBuilder()
    sb.append(str1);
    sb.append(str2);
    sb.append(str3);
    String s = sb.toString();
    
  4. Just out of curiosity, in the case of A to Z you don’t need a string alfabeto to convert from/to 0 to 25. These letters are represented in ASCII (and Unicode/UTF-16) in contiguous positions, where the A is the 65 (hexa 41) and the Z is the 90 (hexa 5A). Thus, with simple numerical operations and cast you can make this conversion without the need for a look-up:

    char letra = 'B';
    int chave = 3;
    
    int posLetra = (int)letra;                // 66
    int codLetra = posLetra - 0x41;           // 1
    int convertida = (codLetra + chave) % 26; // 4
    int posConvertida = convertida + 0x41;    // 69
    char letraFinal = (char)posConvertida;    // 'E'
    

    If this is too confusing for you, ignore, the clarity of the code at first is more important.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.