Hola DeBobiPro,
revisando de nuevo tu código se me ocurren estas cosas:
Esto está un poco roto en MUCHOS casos. Todos se reducen a un solo problema. Cuando la frase contiene algún carácter, ese cambio de N veces es un valor demasiado grande y causa un IndexOutOfBounds (phrase = ".", key = "4").
Ahora, la calidad del código:
. Los nombres de las clases deben ser camelCased.
. ALFA tendría que ser final.
. Código repetitivo que se puede reducir.
Aquí hay una versión mejorada que hace lo que hace el tuyo, pero es más limpia y extensible:
public class Cifrar {
private final String alfabeto;
public Cifrar(String alfabeto) {
this.alfabeto = alfabeto;
}
public String cifrar(String key, String phrase) {
return rot(key, phrase, true);
}
public String decifrar(String key, String phrase) {
return rot(key, phrase, false);
}
private String rot(String key, String phrase, boolean avanzar) {
char[] fuera = new char[phrase.length()];
for(int i = 0; i < phrase.length(); i++) {
char c = phrase.charAt(i);
int indexAlfa = alfabeto.indexOf(c);
// Solo reemplaza caracteres en el alfabeto
if (indexAlfa >= 0) {
// Determina la cantidad de cambios del i'th char en la frase
int keyIndex = i % key.length();
int llave = Integer.parseInt(key.substring(keyIndex, keyIndex + 1));
if(!avanzar)
llave = -llave;
// Obtener el índice de reemplazo en el alfabeto
int reemplazarIndex = (indexAlfa + llave) % alfabeto.length();
if (reemplazarIndex < 0)
reemplazarIndex = alfabeto.length() + reemplazarIndex;
// Reemplazar
c = alfabeto.charAt(reemplazarIndex);
}
fuera[i] = c;
}
return new String(fuera);
}
}
Y para usarlo:
// Da caracteres soportados como cadena, pueden aparecer en cualquier orden.
Cifrar c = new Cifrar(
"abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"1234567890"
);
// key es una secuencia numérica
String key = "123456789";
// Frase y estados codificados/decodificados
String phrase = "aaaaaaaaaa abc def ghi jkl mno pqr stu vwxyz 123 456 7890 -_=+*&^%$#@! () [] {}";
String codificado = c.cifrar(key, phrase);
String decodificado = c.decifrar(key, codificado);
// Imprimir valores
System.out.println(phrase);
System.out.println(codificado);
System.out.println(decodificado);
Salida:
aaaaaaaaaa abc def ghi jkl mno pqr stu vwxyz 123 456 7890 -_=+*&^%$#@! () [] {}
bcdefghijb dfh kmo ikm prt npr uwy Buw zBDFH 246 9ac f9ac -_=+*&^%$#@! () [] {}
aaaaaaaaaa abc def ghi jkl mno pqr stu vwxyz 123 456 7890 -_=+*&^%$#@! () [] {}
ea
Retazo
Ten en cuenta que mi código es más limpio y cumple con los estándares POO.
DeBobiPro, escucha mis consejos para todo lo demás y deja de declarar matrices como si Java fuera C, por favor.
* 1 != 2: Esto es simplemente un meme. El paso 8 es donde las cosas van mal.
Lo mantuve conforme a la implementación de OP a este respecto intencionalmente.
Si bien la llave podría especificarse como int, eventualmente se convertiría en un string en este caso para obtener los dígitos. No es solo un gran número, sino una serie de números para cambiar. Probablemente sería mejor verificar las entradas en el constructor y lanzar una InvalidKeyException comprobada para casos ofensivos en lugar de tomar un int primitivo.
public String cifrar(String key, String phrase) throws InvalidKeySpecException {
verificar(key);
return rot(key, phrase, true);
}
public String decifrar(String key, String phrase) throws InvalidKeySpecException {
verificar(key);
return rot(key, phrase, false);
}
private void verificar(String key)throws InvalidKeySpecException {
if (!key.matches("\\d+"))
throw new InvalidKeySpecException("La clave solo debe contener una secuencia de dígitos");
}
Alternativamente, puedes pasar una matriz int para omitir el análisis de dígitos.
Entonces incluso podrías usar llaves como: int[] key = { -241, 24, 48, -3, 0, 93, 5 };
public String cifrar(int[] key, String phrase) {
return rot(key, phrase, true);
}
public String decifrar(int[] key, String phrase) {
return rot(key, phrase, false);
}
private String rot(int[] key, String phrase, boolean avanzar) {
char[] fuera = new char[phrase.length()];
for(int i = 0; i < phrase.length(); i++) {
char c = phrase.charAt(i);
int indexAlfa = alfabeto.indexOf(c);
// Solo reemplaza caracteres en el alfabeto
if (indexAlfa >= 0) {
// Determina la cantidad de cambios del i'th char en la frase
int keyIndex = i % key.length;
int llave = key[keyIndex];
if(!avanzar)
llave = -llave;
// Obtener el índice de reemplazo en el alfabeto
int reemplazarIndex = (indexAlfa + llave) % alfabeto.length();
if (reemplazarIndex < 0)
reemplazarIndex = alfabeto.length() + reemplazarIndex;
// Reemplazar
c = alfabeto.charAt(reemplazarIndex);
}
fuera[i] = c;
}
return new String(fuera);
}
Y sí, sea cual sea la salida que realmente se desee, mi código sería la opción óptima aquí, especialmente el fragmento final que ofrece más versatilidad y diversidad a pesar de que rompe por completo cualquier parecido con tu 'cifrado' (lo que de hecho es algo bueno en lo que respecta a esto porque el tuyo está roto y limitado a valores positivos de un solo dígito y falla en ciertos escenarios).
De todos modos, DeBobiPro, es una mejora con respecto a las publicaciones de BigBear al ver cómo esto al menos se compila. No es que debas tomar esto como un elogio. O tal vez deberías, ya no estoy seguro.
Saludos