Problem in "encrypting" text program in Java

4

So guys, I have a little problem with one of the workouts I have to do.

The teacher provided .doc with instructions for a " Encryptor Program " that should mask the alphabet and encrypt a text (Enigma style). See Exercise Statement:

Your program should have a method for encrypting and decrypting a document.

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

Let's imagine that each letter has an integer value. We begin with the letter A , which has 0 value. Then B with value 1 , C with value 2 and so on up 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 encrypting a document we will do the following:

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

For example:

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

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

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

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

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

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

If the word is XUXU , using the 5 key, it will be converted to CZCZ . In addition blanks should be converted to a sharp (#). When we decrypt, we will reverse the process. "

I have already done a lot of the code, but some problems arise: in the output text, instead of " # " it breaks a line between the words.

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

Follow 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;
}
}
    
asked by anonymous 05.10.2015 / 09:35

1 answer

2

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

  • A blank space will never appear because Scanner does not return them (by finding one, it returns the word it just read, and calling next it starts reading a new word);
  • You are doing println after converting each word, which introduces a line break between them.
  • When making any reversible conversion of file contents, it is important to preserve all information, so I do not recommend using Scanner . I suggest replacing:

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

    by:

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

    (Note: in this case you can, since the file is ASCII - in practice, also take into account the character encoding - encoding - file)

    And although it is not ideal (for the purpose of this exercise I believe it is 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);
    }
    

    by

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

    This solves your problem of line breaks. Detail: I do not know if it was a mistake when transcribing, but when you check for "invalid key" the if keys 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 try to indentify your code correctly, this makes it easy to see errors of this type.

    Comments

  • Why do you test for all values of 1 to 5 for the key? It would not be simpler to do:

    if ( chave < 1 || 5 < chave ){
        System.out.println("Chave inválida");
    
  • This algorithm ( Cifra César ) basically does the sum / subtraction module 26. The "module ", as you may have studied in math, is basically the rest of the division, which in Java can be done through the % operator:

    int resto = 12 % 5; // 2
    

    It's annoying detail that's the negative numbers ( Java chose to make the result signal the same as the dividend sign ). To get around this, just add 26 while doing the subtraction, so it is guaranteed 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 handwritten letter is not invalid, type a Ç ) a number between 0 and 25 , eliminating the need for that if .

  • In practice, multiple string concatenations can cause performance problems because 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 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();
    
  • Just out of curiosity, in the case of letters from A to Z you do not need a string alfabeto to convert from / to numbers from 0 to 25 . These letters are represented in ASCII (and Unicode / UTF-16) in contiguous positions, where A is 65 (hexa 41 ) and Z is 90 (hexa 5A ) . So with simple numeric and cast operations you can do 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.

  • 08.10.2015 / 21:41