viernes, 10 de abril de 2015

C#. Tipos de datos

En C# los tipos de datos se pueden agrupar en dos tipos: tipos por valor y tipos por referencia.
Los tipos por valor son int, float, double, struct, enum, etc.
Los tipos por referencia son las clases, interfaces, delegados, arrays, etc.

A los tipos por valor no se les puede asignar el valor null. Sin embargo, estos tipos se pueden convertir en tipos anulables, que pueden representar todos los valores del tipo original y el valor null. Para convertir un tipo por valor en anulable sólo hay que añadir el símbolo ? después del tipo.

int? opcion = null;
...
if (opcion != null) Console.WriteLine("La opcion elegida es: {0}", opcion);
else Console.WriteLine("No se ha elegido una opcion");


El código anterior se puede simplificar considerablemente utilizando el operador ??. En el siguiente ejemplo a la cadena se le asigna el valor anterior al operador ?? si la variable opcion no tiene valor nulo, en caso contrario, se le asigna el valor que hay después de dicho operador.

String respuesta = "La opción elegida es: " + opcion.Value.toString() ?? "No se ha elegido una opción";
Console.WriteLine(respuesta);

martes, 7 de abril de 2015

Javascript: marca de agua

Una tarea muy común en el desarrollo de una página web es  la creación de controles de texto con una marca de agua. A continuación se muestra un ejemplo de esta tarea.

<html>
<head>
<script type="text/javascript">
    function establecerMarcaAgua() {
        var txtTexto = document.getElementById("txtTexto");
       
        if (txtTexto.value.length == 0) {
            txtTexto.value= "Introduzca el texto aquí";
            txtTexto.className = "marcaAgua";
        }
    }
    function quitarMarcaAgua() {
        var txtTexto = document.getElementById("txtTexto");
       
        if (txtTexto.value == "Introduzca el texto aquí") {
            txtTexto.value = "";
            txtTexto.className = "texto";
        }
    }
</script>
<style type="text/css">
    .marcaAgua {
        color: gray;
        font-weight: bold;
        font-size: 0.8em;
    }
    .texto {
        color: black;
        font-weight: normal;
        font-size: 1em;
    }
</style>
</head>

<body>
    Texto:
    <input type="text" id="txtTexto" value="Introduzca el texto aquí"
      class="marcaAgua"
      onfocus="quitarMarcaAgua()" onblur="establecerMarcaAgua()" />
</body>
</html>

A continuación se puede ver una versión genérica de las funciones anteriores que se pueden utilizar con múltiples controles.

<html>
<head>
<script type="text/javascript">
    function establecerMarcaAgua(texto, control) {      
        if (control.value.length == 0) {
            control.value= "Introduzca el texto aquí";
            control.className = "marcaAgua";
        }
    }
    function quitarMarcaAgua(texto, control) {      
        if (control.value == "Introduzca el texto aquí") {
            control.value = "";
            control.className = "texto";
        }
    }
</script>
<style type="text/css">
    .marcaAgua {
        color: gray;
        font-weight: bold;
        font-size: 0.8em;
    }
    .texto {
        color: black;
        font-weight: normal;
        font-size: 1em;
    }
</style>
</head>

<body>
    Texto:
    <input type="text" id="txtTexto" value="Introduzca el texto aquí"
        class="marcaAgua"
        onfocus='quitarMarcaAgua("Introduzca el texto aquí", this)'
        onblur='establecerMarcaAgua("Introduzca el texto aquí", this)' />
</body>
</html>

lunes, 6 de abril de 2015

ASP .NET: Procedimiento almacenado

En esta entrada se puede ver un ejemplo de uso de procedimientos almacenados en un método de una aplicación en ASP .NET.

private void Borrar(string IDs) {
  string cs = ConfigurationManager.ConnectionStrings["conStr"].ConnectionString;
  SqlConnection con = new SqlConnection(cs);
  SqlCommand cmd = new SqlCommand("spBorrarEmpleados", con);

  cmd.CommandType = CommandType.StoredProcedure;
  SqlParameter parameter = new SqlParameter("@IDs", IDs);
  cmd.Parameters.Add(parameter); con.Open(); 
  cmd.ExecuteNonQuery();

  con.Close(); }

viernes, 3 de abril de 2015

Android cheat sheet

Esta entrada está dedicada a anotar conceptos básicos para la programación en Android y que es necesario tener presentes en todo momento, ya sea en la memoria o en una entrada en un blog.

- Layouts:
  <FrameLayout  xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"> </FrameLayout>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="horizontal"
      android:padding="25dp"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:weightSum="100"  (peso total de las vistas contenidas)
      android:background="@drawable/imagen_background.png" >
  </LinearLayout>
  <TableLayout  xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
       <TableRow>
         <TextView android:text="celda 1.1" />
         <TextView android:text="celda 1.2" />
      </TableRow>
      <TableRow>
         <TextView android:text="celda 2.1" android:layout_span="2" />
        (ocupa dos columnas)
     </TableRow>
   </TableLayout>
   <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:rowCount="2"
     android:columnCount="3"
     android:orientation="horizontal" >
         <TextView android:text="celda 1.1" />
         <TextView android:text="celda 1.2" />
         <TextView android:text="celda 2.1"  android:layout_columnSpan="2" />
   </GridLayout>
  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     android:layout_width="match_parent"
     android:layout_height="match_parent" >
      <EditText android:id="@+id/TxtNombre"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="text" />
     <Button android:id="@+id/BtnAceptar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/TxtNombre"
        android:layout_alignParentRight="true" />
  </RelativeLayout>
- Controles(views):
  <Button
    android:layout_width="250dp"
    android:layout_height="wrap_content"
    android:text="Pulsar"
    android:layout_gravity="center"
    android:weight="80"  (en realidad, ocupa el 20% del peso total)
    android:textSize="20dp"
    android:id="@+id/btnPulsar" />
  <ToggleButton android:layout_weight="20" android:text="ToggleButton"
    android:id="@+id/tbtn1" android:layout_width="match_parent"
    android:paddingBottom="10dp" android:checked="true"
    android:layout_height="wrap_content" />
  <EditText android:layout_width="match_parent" android:layout_height="wrap_content"
    android:id="@+id/etNombre" android:hint="Escribe el nombre"
    android:password="true" />
- Definir actividad en AndroidManifest.xml:
  <activity android:name=".Splash" android:label="@string/nombre">
    <intent-filter>
      <action android:name="android.intent.action.MAIN" /> (not.ebacelo.android.APP)
      <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>
- Button btnA = (Button) findViewById(R.id.btnA);
   TextView tvTexto = (TextView)findViewById(R.id.txtTexto);
   final EditText etEntrada= (EditText)findViewById(R.id.etEntrada);
   etEntrada.setInputType(InputType.TYPE_CLASS_TEXT |
     InputType.TYPE_TEXT_VARIATION_PASSWORD);
   tvTexto.setGravity(Gravity.CENTER);
- btnA.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
      Random rand = new Random();
      if (cadena.contentEquals("texto")
        txtTexto.setText("Texto para la vista");
        txtTexto.setTextColor(Color.BLUE);
        txtTexto.setTextSize(rand.nextInt(40);
    }
  }
  //Otra opción es implementar la interfaz View.OnClickListener y
  //el método onClick dentro de la clase correspondiente.
  //btnA.setOnClickListener(this)
- protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.splash);

    ourSong = MediaPlayer.create(Splash.this,  R.raw.sonido);
    ourSong.start();

    Thread timer = new Thread() {
       public void run() {
         try {
           sleep(5000);
         } catch (InterruptedException e) {
           e.printStackTrace();
         } finally {
           Intent openSplash = new Intent("not.ebacelo.android.SPLASH");
           startActivity(openSplash);
         }
       }
     }
  }
- protected void onPause() {
    super.onPause();
    ourSong.release();
    finish();
  }

- Lista de elementos:
  public class Menu extends ListActivity {
    String elementos[] = {"elemento1", "elemento2", "elemento3", "elemento4"};

    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setListAdapter(new ArrayAdapter<String>(Menu.this,
         android.R.layout.simple_list_item_1, elementos));
    }
    protected void onListItemClick(ListView l, View v, int position, long id) {
      super.onListItemClick(l, v, position, id);
      String elementoSeleccionado = elementos[position];
      try {
        Class miClase = Class.forName("not.ebacelo.android.splash");
        Intent miIntent = new Intent(Menu.this, miClase);
        startActivity(miIntent);
      } catch (ClassNotFounException e) {
        e.printStackTrace();
      }
    }
  }

lunes, 23 de marzo de 2015

Javascript: cosas a recordar

Hoy voy a anotar aquí una serie de cosas que es recomendable tener en cuenta a la hora de trabajar con Javascript. Espero que estas anotaciones me sirvan de recordatorio cada vez que tenga que trabajar con Javascript y, de paso, que puedan resultarle útiles a cualquiera que lea este blog.

- Intérprete javascript online: jsbin.com

- Usar .textContent en lugar de innerHTML por el bien de la compatibilidad con
  todos los navegadores

- Usar doc.getElementById("elemento").value en lugar de .value (este último no
  funciona en IE)
- document.getElementById("imagen").getAttribute("src");
- document.getElementById("imagen").setAttribute("src", "imagen.jpg");

- Colocar las etiquetas <script> justo antes de la etiqueta de cierre </body>. Los
  navegadores paran la  descarga del HTML al encontrar etiquetas <script> para
  descargar los ficheros .js. También se puede usar atributo
  async de <script> en navegadores modernos.

- Sensible a mayúsculas y minúsculas.

- Comentarios: // (única línea) y /* comentario */ (varias líneas)

- Tipos de datos: Number, Boolean, String. Para definir una variable usamos var.

- parseInt() y parseFloat() para convertir strings a números enteros y decimales.
  isNaN() para comprobar si es un número.
- Number(prompt("Introduce un número: ", "");  //convierte una cadena a número

- cadena1.concat(" ", cadena2);
  también se puede utilizar: cadena1 + " " + cadena2.

- cadena1 = "Hola"; cadena2 = "mundo"; cadena1.concat(" ", cadena2, "!");

- cadena1.toUpperCase(); cadena2.toLowerCase();

- "cadena de texto".length

- trim(): eliminar blancos, cadena1.replace("cadena1", "cadena2");
  El primer parámetro de replace puede   ser una expresión regular

- substring(inicio, fin); substr(inicio, contador); slice(inicio, fin);
  substr no funciona en IE8 y anteriores, slice no intercambia inicio y fin cuando   inicio>fin

- cadena1.indexOf("c"); cadena2.lastIndexOf("d");

- document.getElementById("idElemento");

- prompt("Mensaje a mostrar", "texto por defecto para devolver si el usuario no
  introduce nada");

- Definir arrays:
  var arrayVacio = []; var miArray = ["uno", "dos", "tres"];
  var array10 = new Array(10);
  var array2d = new Array(3); for (var i=0; i<3 data-blogger-escaped-array2d=""
  data-blogger-escaped-br="" data-blogger-escaped-i="" data-blogger-escaped-new="">
  Array(3);} - miArray.push("valor a añadir");
- var elemento = miArray.pop(); //devuelve el último elemento del array y lo
  elimina del mismo.
- miArray.shift(); //obtiene el primer elemento del array y lo quita del mismo
- miArray.unshift("valor"); //añade un valor como primer elemento del array.
- miArray.sort(); //por defecto supone que los elementos son strings y los ordena.
- miArray.sort(function(a,b) {return a-b}); //ordena de menor a mayor
- var a = miArray.sort(function(a,b) {return b-a}); ó a.reverse();
- miArray.splice(índice, contadorEliminar, elemento1...elementoN); //añadir y
  eliminar
- miArray.filter(esPar(value, index, array) { return value % 2; }); //sólo los
  pares
- miArray.filter(function (value, index, array) { return array.indexOf(value) ==
  index; }); //no repetidos

- Se puede usar una función antes de su definición (function hoisting).
- Funciones anónimas: var sumar = function (x, y) { return x+y }; sumar(1, 2);
- arguments.length; arguments[i]; //es un objeto no un array
  var arrayArgs = Array.prototype.slice.call(arguments); //convertir en array
- Lanzar exceptiones: throw {error: "Número inválido", message: "No es un formato
  numérico válido"}

- window.onerror = function(msg, url, line) {
  alert("Mensaje: " + msg + "\nURL: " + url + "\nLinea: " + line);
  return true; }
- <img src="imagenNoExiste.jpg" onerror="imageErrorHandler()" />
  function imageErrorHandler(msg, url, line) {alert("Hay un problema
  con la imagen");}

- var fecha = new Date(); fecha = new Date("March 26, 2015 11:06:00");
- var fecha = new Date(year, month, day, hour, minute, second, millisecond);
- fecha.getFullYear(); fecha.getMonth(); fecha.getDate(); fecha.getDay();
  fecha.getHours(); fecha.getMinutes(); fecha.getSeconds();

- var idIntervalo = window.setInterval(funcion, intervaloMilisegundos);
  window.clearInterval(idIntervalo);
- var idTemporizador = window.setTimeout(funcion, esperaMilisegundos);
  window.clearTimeout(idTemporizador);

- if (confirm("¿Está seguro?")) {return true; } else {return false;}
  onclick="return confirmOnSubmit()"

- Atributos de la propiedad style (ver aquí).
- Eventos de elementos: onclick, onblur, onmouseover, onmouseout,...
- Eventos de DOM: document.getElementById("idElemento").onmouseover =
  nombreFuncion;
- idBtn.addEventListener("mouseover", changeColorOnMouseOver, false);
- idBtn.removeEventListener("mouseover", changeColorOnMouseOver);
  (Disponibles en IE9+ y otros navegadores modernos).
- idBtn.attachEvent("onclick", clickEventHandler);
- idBtn.detachEvent("onclick", clickEventHandler);
  (Soportado en IE8 y versiones anteriores)
- if (btn.addEventListener) {... (será true para IE9+ y otros navegadores
  modernos).
- <input type="button" value="Pulsar" id="btn"
  onclick="obtenerDetallesEvento(event)" />
  function obtenerDetallesEvento(event) {   
     var sourceElement;
     if (event.srcElement) {   //soportado en IE8-
        sourceElement = event.srcElement;
     } else {
        sourceElement = event.target;   //soportado en IE9+ y otros
     }
     return event.type + " " + event.clientX + " " + event.clientY + " " +
     sourceElement.type + " " + sourceElement.tagName;
  }

- Utilizar event bubbling para evitar asignar manejador en muchas ocasiones.
- Se puede activar event capturing poniendo el último parámetro del
  método .addEventListener a TRUE. Si es FALSE, se produce event
  bubbling. Se pueden activar los dos si se añade dos veces el manejador con
  los valores distintos para el último parámetro.
- Cancelar event bubbling:
  event = event || window.event;  //por compatibilidad con IE8-
  if (event.stopPropagation) {
    event.stopPropagation();  //IE9+ y otros
  } else {
    event.cancelBubble = true;  //IE8-
  }

- Evitar funcionamiento por defecto del navegador (click botón derecho,
  pulsar enlace):
  <body oncontextmenu="return false">
  document.oncontextmenu = deshabilitaPorDefecto;

  function deshabilitaPorDefecto(event) {
    event = event || window.event;
    if (event.preventDefault) {  //IE9+ y otros
      event.preventDefault();
    } else {
      event.returnValue = false;  //IE8-
    }

  Prevenir que un enlace nos lleve a otra página:
  <a href="http://www.google.com" onclick="return false" >Google</a>
  <a href="http://www.google.com" onclick="deshabilitaPorDefecto(event)">
  Google
  </a>

- Detectar el botón del ratón pulsado:
  <input type="button" value="Click me" onmouseup="obtenerClickRaton(event)" />
  function obtenerClickRaton(event) {
    var botonPulsado;
    if (event.which)  {
      botonPulsado = event.which;  //IE9+ y otros
    } else {
      botonPulsado = event.button;  //IE8-
    }
  }

- Ventanas emergentes:
  window.open(URL, nombre, caracteristicas, reemplazar);
  <input type="button" value="Abrir ventana"
  onclick="window.open('http://www.google.com', '_self ', 'height=100,width=150',
  false)" />

  var ventana;
  function abrirVentana() {
    ventana = window.open("http://www.google.com", "ventana", "height=100,
    width=100");
  }
  function cerrarVentana() { ventana.close(); }


- Expresiones regulares:
  Herramienta gratuíta: Expresso Librería de expresiones: Regexlib
  var valor= document.getElementById("txtCadena").value;
  var resultado = valor.match(/\d+/g);
  if (resultado != null) {
    for (var i=0; i<resultado.length;i++) {
      document.getElementById("txtResultado").value += resultado[i] + "\r\n";
    }
  }
    \d: valor numérico (\d+: 1 o varios elementos numéricos consecutivos)
    /g: búsqueda global
    \d{5,}: números de 5 dígitos o más ---  \b\d{4}\b:  números de justo 4 dígitos
    [0-9]{5}: equivalente al anterior
    \b[a-zA-Z]\b: palabras con letras sin tilde
    [a|b|c]: busca cualquiera de los caracteres incluídos

  var cadena="Cadena con números: 10 11 222";
  cadena.match(/\d+/g); //g: global, i: insensible a mayúsculas y minúsculas,
  m: multilínea
  cadena.replace("/\d+/g, "XXX");  //reemplaza números por XXX
  cadena.split("/\d+/");
  var posicion = cadena.search(/\d+/);

  var regexp = /\d+/g;   //expresión regular literal (mejor rendimiento si
  la expresión regular no varía)
  var regexp = new RegExp("\\d+", "gim");  //global, ignore case, multiline
  regexp.exec(cadena);  //busca coincidencia y devuelve la primera encontrada
  regexp.test(cadena); //busca coincidencia y devuelve true o false
  regexp.toString();  //devuelve cadena con la expresión regular
  regexp.global; regexp.ignoreCase; regexp.multiline; regexp.source;

- Validación lado cliente:
  function validarLogName() {
    var txtName = document.getElementById("txtName");
    var name= txtName.value;
    var regExName = /[a-zA-Z0-9]+/;

    txtName.style.color = "white";
    if (regExName.text(name))
      txtName.style.backgroundColor = "green";
    else
      txtName.style.backgroundColor = "red";
  }

- Herramientas para reducir código Javascript (minification):
  - http://crockford.com/javascript/jsmin
  - https://marijnhaverbeke.nl/uglifyjs (online)



martes, 24 de septiembre de 2013

Método de cifrado inventado (en Android)

En este caso voy a publicar una pequeña aplicación muy parecida a la de la publicación anterior, al menos en apariencia. En este caso, la principal diferencia con respecto a la anterior radica en el algoritmo de cifrado que se aplica. Se trata de un método creado por mi mismo mezclando sustitución y transposición en el mismo algoritmo.
Este algoritmo consiste en dos pasos:

  •  Primero se sustituye cada carácter del mensaje por el correspondiente a su posición en el alfabeto con un desplazamiento 9 si se trata de una letra y 5 si es un dígito. En caso de ser otro carácter no se modificará.
  • En segundo lugar, divide el mensaje resultante de aplicar el proceso anterior en partes de 3 caracteres y se invierte el orden de los caracteres en cada grupo. Después se vuelven a agrupar y así se obtiene el mensaje final cifrado.
La implementación del algoritmo de cifrado/descifrado se hace en una clase independiente con lo que es muy fácil cambiar el algoritmo utilizado sin tener que modificar la interfaz de usuario, o haciendo cambios mínimos.
A continuación podéis ver el código y descargar un fichero para instalarla en un dispositivo Android.


package com.example.firstapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ");


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     
       
        Button btnConvertir = (Button)findViewById(R.id.btnConvertir);
        Button btnLimpiar = (Button)findViewById(R.id.btnLimpiar);
     
        final EditText etPlano = (EditText)findViewById(R.id.etPlano);
        final EditText etCifrado = (EditText)findViewById(R.id.etCifrado);
     
        btnLimpiar.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
etPlano.setText("");
etCifrado.setText("");
}
});
     
        btnConvertir.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
String textoPlano = etPlano.getText().toString();
String textoCifrado = etCifrado.getText().toString();
int txtLen = etPlano.length();
int cifrLen = etCifrado.length();

ECipherDecipher ecd = new ECipherDecipher();

if ((txtLen != 0) || (cifrLen !=0))
{
if (txtLen > 0)
{
String contenidoCifrado = ecd.cifrar(textoPlano);
etCifrado.setText(contenidoCifrado);
}
else
{
String contenidoPlano = ecd.descifrar(textoCifrado);
etPlano.setText(contenidoPlano);
}
}
}
});
    }

}

El código correspondiente a la implementación del algorirtmo se muestra en el código siguiente.

package com.example.firstapp;

public class ECipherDecipher {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ");
private final String abc2 = new String("0123456789");

//Definición del desplazamiento en la parte de cifrado por sustitución (César)
private int DESPLAZAMIENTO_CARACTERES = 9;
private int DESPLAZAMIENTO_DIGITOS = 5;

public ECipherDecipher()
{

}

public String cifrar(String cadena)
{
char caracterCifrado;
int posCaracterPlano;
int posCaracterCifrado;
int endPosSubCadena;
StringBuilder sbTextoIntermedio = new StringBuilder();
StringBuilder sbTextoCifrado = new StringBuilder();
StringBuilder subCadena3;

//Convertimos a mayúsculas
String texto = cadena.toUpperCase();

//Para cada caracter del texto
for (int i=0; i<texto.length(); i++)
{
char caracter = texto.charAt(i);
//Si es alfabético
if (Character.isLetter(caracter))
{
//Desplazamiento de cada carácter 9 posiciones
posCaracterPlano = abc.indexOf(caracter);
posCaracterCifrado = (posCaracterPlano + DESPLAZAMIENTO_CARACTERES) % abc.length();
caracterCifrado = abc.charAt(posCaracterCifrado);
sbTextoIntermedio.append(caracterCifrado);
}
else if (Character.isDigit(caracter))
{
//Si es numérico
//Desplazamiento de cada dígito 5 posiciones
posCaracterPlano = abc2.indexOf(caracter);
posCaracterCifrado = (posCaracterPlano + DESPLAZAMIENTO_DIGITOS) % abc2.length();
caracterCifrado = abc2.charAt(posCaracterCifrado);
sbTextoIntermedio.append(caracterCifrado);

}
else
{
//En otro caso no modificar el carácter
sbTextoIntermedio.append(caracter);
}
}

//Con el texto convertido anteriormente cogemos subcadenas de longitud 3
//y los invertimos.
while (sbTextoIntermedio.length()>0)
{
endPosSubCadena = 3;

if (sbTextoIntermedio.length()< 3)
{
endPosSubCadena = sbTextoIntermedio.length();
}
subCadena3 = new StringBuilder(sbTextoIntermedio.substring(0, endPosSubCadena));
sbTextoIntermedio = sbTextoIntermedio.delete(0, endPosSubCadena);
subCadena3 = subCadena3.reverse();
sbTextoCifrado.append(subCadena3);
}

return sbTextoCifrado.toString();
}

public String descifrar(String texto)
{
char caracterDescifrado;
int posCaracterCifrado;
int posCaracterDescifrado;
int endPosSubCadena;
StringBuilder sbTextoIntermedio = new StringBuilder();
StringBuilder sbTextoCifrado = new StringBuilder();
StringBuilder sbTextoPlano = new StringBuilder();
StringBuilder subCadena3;

sbTextoCifrado = new StringBuilder(texto.toUpperCase());

//Con el texto cogemos subcadenas de longitud 3 y los invertimos.
while (sbTextoCifrado.length()>0)
{
//Posición de fin de la subcadena
endPosSubCadena = 3;

if (sbTextoCifrado.length()< 3)
{
endPosSubCadena = sbTextoCifrado.length();
}
subCadena3 = new StringBuilder(sbTextoCifrado.substring(0, endPosSubCadena));
sbTextoCifrado = sbTextoCifrado.delete(0, endPosSubCadena);
subCadena3 = subCadena3.reverse();
sbTextoIntermedio.append(subCadena3);
}

//Para cada caracter del texto
texto = sbTextoIntermedio.toString();

for (int i=0; i<texto.length(); i++)
{

char caracter = texto.charAt(i);
//Si es alfabético
if (Character.isLetter(caracter))
{
//Desplazamiento de cada carácter -9 posiciones
posCaracterCifrado = abc.indexOf(caracter);
posCaracterDescifrado = (posCaracterCifrado - DESPLAZAMIENTO_CARACTERES +
(abc.length())) % abc.length();
caracterDescifrado = abc.charAt(posCaracterDescifrado);
sbTextoPlano.append(caracterDescifrado);
}
else if (Character.isDigit(caracter))
{
//Si es numérico
//Desplazamiento de cada dígito -5 posiciones
posCaracterCifrado = abc2.indexOf(caracter);
posCaracterDescifrado = (posCaracterCifrado - DESPLAZAMIENTO_DIGITOS +
(abc2.length())) % abc2.length();
caracterDescifrado = abc2.charAt(posCaracterDescifrado);
sbTextoPlano.append(caracterDescifrado);
}
else
{
//En otro caso no modificar el carácter
sbTextoPlano.append(caracter);
}
}

return sbTextoPlano.toString();
}
}

La apariencia de la aplicación es casi igual a la de la aplicación descrita en la entrada anterior del blog.


El fichero de instalación se puede descargar aquí.

Cifrado César (aplicación en Android)

En esta entrada voy a mostrar una pequeña aplicación que permite cifrar mensajes utilizando el método César. Del mismo modo, permite descifrar los mensajes cifrados utilizando el proceso inverso. En este caso la interfaz de usuario es muy sencilla, la parte un poco más compleja es el código que realiza las operaciones de cifrado/descifrado.
A continuación os muestro el código y alguna imagen de la aplicación en funcionamiento. En primer lugar se muestra el código correspondiente a la actividad principal.

package com.example.firstapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;

public class MainActivity extends Activity {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ");
private int desplazamiento = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     
        Spinner spin1 = (Spinner)findViewById(R.id.spin1);
     
        ArrayAdapter<CharSequence> adaptador = ArrayAdapter.createFromResource(this, R.array.desplazamientos,
        android.R.layout.simple_spinner_item);
        adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spin1.setAdapter(adaptador);
     
     
        Button btnConvertir = (Button)findViewById(R.id.btnConvertir);
        Button btnLimpiar = (Button)findViewById(R.id.btnLimpiar);
     
        final EditText etPlano = (EditText)findViewById(R.id.etPlano);
        final EditText etCifrado = (EditText)findViewById(R.id.etCifrado);
     
        btnLimpiar.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
etPlano.setText("");
etCifrado.setText("");
}
});
     
        etCifrado.setOnKeyListener(new EditText.OnKeyListener() {
@Override
public boolean onKey(View arg0, int arg1, KeyEvent arg2) {
if (etPlano.getText().toString().compareTo("") != 0)
{
etPlano.setText("");
}
return false;
}
        });
     
        spin1.setOnItemSelectedListener(new OnItemSelectedListener() {

@Override
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
desplazamiento = pos;
}

@Override
public void onNothingSelected(AdapterView<?> arg0) {
desplazamiento = 0;
}
       
        });
     
        btnConvertir.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
String textoPlano = etPlano.getText().toString();
String textoCifrado = etCifrado.getText().toString();
int txtLen = etPlano.length();
int cifrLen = etCifrado.length();
CifradorDescifradorSustitucion cifDecif = new CifradorDescifradorSustitucion(desplazamiento);

if ((txtLen != 0) || (cifrLen !=0))
{
if (txtLen > 0)
{
String contenidoCifrado = cifDecif.cifrar(textoPlano);
etCifrado.setText(contenidoCifrado);
}
else
{
String contenidoPlano = cifDecif.descifrar(textoCifrado);
etPlano.setText(contenidoPlano);
}
}
}
});
    }

}

En segundo lugar se muestra el código de la clase dónde se implementa el cifrado y descifrado mediante el método César.

package com.example.firstapp;

public class CifradorDescifradorSustitucion {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ0123456789");

private int desplazamiento;
private String textoPlano;
private String textoCifrado;

public CifradorDescifradorSustitucion() {
desplazamiento = 0;
}

public CifradorDescifradorSustitucion(int desplazamiento) {
this.desplazamiento = desplazamiento;
}

public String descifrar(String textoCifrado) {
char caracterCifrado = ' ';
char caracterPlano = ' ';

textoCifrado = textoCifrado.toUpperCase();
StringBuilder textoPlano = new StringBuilder(textoCifrado.length());

for (int i = 0; i < textoCifrado.length(); i++) {
caracterCifrado = textoCifrado.charAt(i);
if (abc.contains(String.valueOf(caracterCifrado))) {
int posCaracterCifrado = abc.indexOf(caracterCifrado);
int posCaracterPlano = ((posCaracterCifrado - desplazamiento) + (abc
.length() + 1)) % (abc.length());
caracterPlano = abc.charAt(posCaracterPlano);
} else {
caracterPlano = caracterCifrado;
}
textoPlano.append(caracterPlano);
}

return textoPlano.toString();
}

public String cifrar(String textoPlano) {
char caracterCifrado = ' ';
char caracterPlano = ' ';

textoPlano = textoPlano.toUpperCase();
StringBuilder textoCifrado = new StringBuilder(textoPlano.length());

for (int i = 0; i < textoPlano.length(); i++) {
caracterPlano = textoPlano.charAt(i);
if (abc.contains(String.valueOf(caracterPlano))) {
int posCaracterPlano = abc.indexOf(caracterPlano);
int posCaracterCifrado = (posCaracterPlano + desplazamiento)
% (abc.length());
caracterCifrado = abc.charAt(posCaracterCifrado);
} else {
caracterCifrado = caracterPlano;
}
textoCifrado.append(caracterCifrado);
}
return textoCifrado.toString();
}

public int getDesplazamiento() {
return desplazamiento;
}

public void setDesplazamiento(int desplazamiento) {
this.desplazamiento = desplazamiento;
}

public String getTextoPlano() {
return textoPlano;
}

public void setTextoPlano(String textoPlano) {
this.textoPlano = textoPlano;
}

public String getTextoCifrado() {
return textoCifrado;
}

public void setTextoCifrado(String textoCifrado) {
this.textoCifrado = textoCifrado;
}

}

Por último se puede ver el código xml correspondiente al layout (muy sencillo como ya comenté anteriormente).

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Spinner
        android:id="@+id/spin1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/textView3"
        android:layout_below="@+id/textView1" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:text="@string/titulo_spin1" />

    <EditText
        android:id="@+id/etPlano"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/textView2"
        android:ems="10"
        android:hint="Texto plano aquí..."
        android:lines="4" >

        <requestFocus />
    </EditText>

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/etCifrado"
        android:layout_below="@+id/etPlano"
        android:layout_marginTop="45dp"
        android:text="@string/texto_cifrado" />

    <EditText
        android:id="@+id/etCifrado"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/etPlano"
        android:layout_below="@+id/textView3"
        android:ems="10"
        android:hint="Texto cifrado aquí..."
        android:lines="4" />

    <Button
        android:id="@+id/btnConvertir"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/etCifrado"
        android:layout_below="@+id/etCifrado"
        android:layout_marginTop="17dp"
        android:layout_toRightOf="@+id/textView3"
        android:text="@string/convertir" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/spin1"
        android:layout_below="@+id/spin1"
        android:text="@string/texto_plano" />

    <Button
        android:id="@+id/btnLimpiar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/btnConvertir"
        android:layout_alignBottom="@+id/btnConvertir"
        android:layout_alignLeft="@+id/etCifrado"
        android:text="Limpiar" />

</RelativeLayout>

El archivo de instalación podéis descargarlo aquí.