sábado, 7 de febrero de 2015

Expresiones regulares



Las expresiones regulares son el típico ejemplo de las cosas que si no las usan con frecuencia se olvidan y tienes que ir tirando de Google para recordarlas.

Por si no las conocéis todavía, son una gran ayuda a la hora de buscar y reemplazar textos, aunque tienen una pequeña curva de aprendizaje. Una vez superada, no puedes vivir sin ellas.

Tiene soporte en los lenguajes, entornos de desarrollo y en los editores de textos más conocidos.

Podemos practicar las búsquedas con Notepad++,  un editor free source code muy completo.

Una guía de referencia rápida de expresiones regulares que suelo consultar es http://msdn.microsoft.com/es-es/library/az24scfc.aspx

Tienes más info en



Repasemos con ejemplos más útiles.

Caracteres

.
Cualquier carácter que no sea el salto de linea \n
m.sa
La masa está en la mesa de la musa
[chars]
Coincide con cualquier carácter de los especificados
m[ae]sa
La masa está en la mesa de la musa
[^chars]
Cualquier carácter de los que NO estén encerrados por corchete
[^aem]
mesa 18
\t
Caracter de tabulación
\r
Caracter de Retorno de carro (ASCII 13)
\n
Caracter de Nueva Linea (ASCII 10)
Recordad que el salto de línea de Windows es \n\r  (chr 10 + chr 13)
\
Seguido de un carácter, es la forma de representar ese carácter si coincide con símbolos reservados. P.Ej,  \.   \*  \(   \)
\x00
Caracter ascii especificado en hexadecimal.
Por ejemplo, “\x23” seleccionará “#”  (ascii 35)

 

Clases de carácter

\w
Cualquier carácter numérico o letra
\w
P#5.8
\W
Cualquier carácter que no sea numérico o letra
\W
P#5.8
\s
El carácter de espacio en blanco
\S
Cualquier caracter que no sea un espacio en blanco
\d
Cualquier dígito decimal
 
 
a18
\D
Cualquier carácter que no sea un dígito decimal
 
a18

 

 

Cuantificadores

Los cuantificadores añaden cantidad de repeticiones a los caracteres

*
Repetición ninguna o más veces
+
Repetición una o más veces
Ej: Cualquier número que se repita una o más veces
\d+
d189b40h
?
Cero o una vez
Ej: Cualquier cifra, seguida opcionalmente de una letra, y otra cifra
\d\w?\d
1A9  19 1
{n}
Exactamente N veces
Ej de extracción de una fecha: 2 digitos, la barra /, 2 digitos, la barra /, 4 digitos 
\d{2}/\d{2}/\d{4}
El 15/08/2014 llegaré a 2/300
{n,}
Al menos N veces
Elíge las palabras de al menos 3 letras 
\w{3,}
arbol, ale, so
{n,m}
De N a M veces
Ej de extracción de una fecha que puede contener 1 o 2 digitos en días y meses, y 4 digitos en año
\d{1,2}/\d{1,2}/\d{4}
El 15/8/2014 llegaré a 2/300

 

Anclajes

^
Inicio de línea
 
Selecciona la línea entera que empieza por número
^\d.*$
frase 1.
2 frase
Frase 3.
$
Fin de línea
 
Selecciona la última palabra que no acabe en punto
\w+[^.]$  
ó
\w+$
La frase 1.
La 2ª frase
Frase numero 3.
\b
Marca la posición de una palabra limitada por espacios en blanco, puntuación o el inicio/final de una cadena.
 
Ej: Selecciona las palabras que comiencen por vocal
\b[aeiou]\w*\b
encina,pino,
romero,olmo
,almendro,cerezo.

 
 

Greedy and Lazy  (búsquedas tardías y tempranas)

Por defecto, todas estas búsquedas que hemos visto son búsquedas tardías. Es decir, tienden a englobar el mayor número de elementos.
Si hacemos una búsqueda de los tags <span> de un html devolverá del primero al último.

 

<span>.*</span>
Esta es la <span>casa</span> con las mejores <span>vistas</span>

 

Como veis, el modo tardío ha seleccionado desde el primer span al último span, incluyendo el texto del medio.  Si queremos cambiar el comportamiento de tardío (greedy) a tempranp (lazy), usaremos el símbolo ?

<span>.*?</span>
Esta es la  <span>casa</span> con las mejores <span>vistas</span>

 

Grupos

Los grupos se pueden usar para posicionarnos en un punto de la búsqueda sin llegar a seleccionarlo. Es algo duro de entender, pero con un ejemplo se ve mejor.

En el ejemplo anterior, vimos que con la expresión regular <span>.*?</span> seleccionábamos los span, incluyendo los tags. Si lo que queremos es seleccionar el CONTENIDO del span haciendo referencia al propio tag SPAN sin seleccionarlo,  los introduciremos dentro de grupos de búsqueda anterior y posterior.

(?<=expr) posiciona el resultado de la búsqueda tras el resultado de expr, sin llegar a seleccionar la expresión

(?=expr) posiciona el resultado de la búsqueda justo donde comienza la expresión, sin llegar a seleccionarla

Con lo que podemos conseguir seleccionar el contenido de 2 tags html

(?<=<span>).*?(?=</span>)
Esta es la <span>casa</span> con las mejores <span>vistas</span>

 

Con los grupos también podemos usar condicionales, es decir, si se cumple una condición u otra

En este caso, elegiremos entre las marcas de inicio de palabra,  las fechas que sean 1 o 2 cifras, barra, 1 o 2 cifras , barra, y o 2 o 4 cifras

\b\d{1,2}/\d{1,2}/(\d{4}|\d{2})\b
 
El 15/8/2035 llegaré a 2/300
El 3/12/15 llegaré a 2/300
El 3/12/340 llegaré a 2/300

 

Otra característica de los grupos es que los resultados los podemos introducir en variables para tratarlos desde c#.

Un grupo puede definirse con nombre o con índice.

(expr)  Grupo con índice

(?<nombre>expr)  Grupo con nombre de variable

^\w+,\sa\s(?<DIA>\d{1,2})\sde\s
(?<MES>\w+\b)\sde\s(?<AÑO>\d{4})$
Valencia, a 4 de febrero de 2018
Madrid, a 15 de abril de 2019

Traducido “al castellano”, quedaría de la siguiente forma:

“Desde el inicio de la línea, selecciona letras hasta llegar a una coma, un espacio, una “a”, un espacio, 1 o 2 dígitos que los introduces en la variable “DIA”, un espacio, “de”, un espacio, texto que lo introduces en la variable “MES”, un espacio, “de”, un espacio, 4 dígitos que los introduces en la variable “AÑO”

Otro ejemplo de grupos: Extraer  fechas que están en un formato algo mezclado

^\w{2}(?<AÑO>\d{4})(?<MES>\d{2})(?<DIA>\d{2})_
(?<H>\d{2}):(?<M>\d{2}):(?<S>\d{2})\.txt$
DW20141128_08:59:48.txt
UP20141115_09:39:46.txt
DW20141106_11:45:20.txt

 

Pasado a c#, este ejemplo se quedaría de la siguiente manera.




 
Ejemplos para validaciones
 


IBAN (España)
ES\d{2}[ ]\d{4}[ ]\d{4}[ ]\d{4}[ ]\d{4}[ ]\d{4}|ES\d{22}
Codigo postal
^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$
Número
telefono (España)
^[0-9]{2,3}-? ?[0-9]{6,7}$
Visa
 
^((67\d{2})|(4\d{3})|(5[1-5]\d{2})|(6011))(-?\s?\d{4}){3}|(3[4,7])\ d{2}-?\s?\d{6}-?\s?\d{5}$
Contraseña segura
(?!^[0-9]*$)(?!^[a-zA-Z]*$)^([a-zA-Z0-9]{8,10})$
URL
^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)( [a-zA-Z0-9\-\.\?\,\'\/\\\+&amp;%\$#_]*)?$
Correo electrónico
 
^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(( [a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$

 

Conclusión

Las expresiones regulares, como habéis podido comprobar, es una herramienta muy potente que nos puede sacar de muchos apuros y ahorrarnos docenas de bucles infernales para trastear con textos.

 

Espero que os sea de provecho.

 

 

 

miércoles, 12 de noviembre de 2014

Visual Studio 2013 Community Edition

Visual Studio Community Edition
Microsoft acaba de sacar hoy una nueva versión de Visual Studio 2013 totalmente gratuita, que elimina las limitaciones que teníamos con las versiones Express, pudiendo instalar extensiones y eliminando la barrera que había anteriormente en la versión Express con versiones Web y Desktop.

Esta versión es gratuita para profesionales, estudiantes y pequeños equipos hasta 5 programadores.

Más información y descarga en http://www.visualstudio.com/news/vs2013-community-vs

ASP.NET 5 multiplataforma
ASP.Net 5 estará disponible para Windows, Mac y Linux. Incluirán un web server propio.


Otras novedades
- El .NET core Framework pasa a ser OpenSource
- Se prepara un CLR de .NET para Mac y para Linux, por lo que se podrá programar con .NET en estas plataformas

Tenéis más información en el blog de Scott Hanselman.


La verdad es que son muy buenaa noticia para los desarrolladores de .NET.







lunes, 11 de agosto de 2014

Dapper, un micro ORM a tener en cuenta

Los ORM (Mapeo objeto – relacional) son una pieza fundamental en el desarrollo de nuestras aplicaciones.
Permite interactuar con la base de datos mediante objetos y listas de objetos, olvidándonos de los tediosos datasets.

Cuando hablamos de ORM nos viene a la cabeza Entity Framework y Nhibernate, pero existen también los llamados micro-orm que son bastante más ligeros y, siendo más simples que los ORM convencionales,  cumplen su función banstante bien, como pueden ser, entre otros, Massive, Simple.Data, Peta Poco y Dapper

Dapper es el ORM en el que se basa Stack Overflow y algunas otras webs.

https://code.google.com/p/dapper-dot-net/

Según los benchmarks en su web, llega a ser bastante más rápido que Entuty Framework y Nhibernate en realizar los Selects.

Dapper se puede usar a partir del Framework 3.5, aunque es recomendable Framework a partir de 4 para usar el potencial de las clases dynamic

Vamos a trastear un poco con él a ver cómo funciona.


Instalación
En primer lugar, decir que se trata de un método extensor de IDbConnection, por lo que podemos utilizar cualquier objeto que implemente IDbConnection( Sql Server, Oracle, MySql, ...)

Podemos descargarlo a través de NuGet, o directamente adjuntando la clase SqlMapper.cs a vuesto proyecto.


Consultas sin objetos mapeados
Para obtener una lista de objetos dinamic sin tener que usar ninguna clase:
            

string connectionString = "Data Source=(localdb)\\v11.0;Initial Catalog=NorthWind;Integrated Security=True";
IDbConnection conn= new SqlConnection(connectionString);
conn.Open();

var empleados = conn.Query("select * from employees where country = @pais", new { @pais = "UK" });
foreach (var empleado in empleados)
     Console.WriteLine("{0} {1} - {2}", empleado.FirstName, empleado.LastName, empleado.Country);
conn.Close();
Console.ReadKey();
Nótese que estamos usando Parameters en una clase anónima, por lo que evitamos inyección de SQL.

Consultas sin objetos mapeados en .Net 3.5
Si estuviéramos trabajando con Framework 3.5, bastará con añadir el símbolo de compilación condicional "CSHARP30" en las propiedades del proyecto - Compilar, y obtendremos los valores en IDictionary
var empleados = conn.Query("select * from employees where country = @pais", new { @pais = "UK" });
foreach (var empleado in empleados)
     Console.WriteLine("{0} {1} - {2}", empleado["FirstName"], empleado["LastName"], empleado["Country"]);

Consultas con objetos mapeados
Ahora añadimos una clase POCO de Empleados, y veamos que sigue funcionando, esta vez devolviendo un IEnumerable<T>
public class Employees
{
    public int EmployeeId;
    public string LastName;
    public string FirstName;
    public string Country;
}


var empleados = conn.Query<employees>("select * from employees where country = @pais", new { @pais = "UK" });
foreach (var empleado in empleados)
     Console.WriteLine("{0} {1} - {2}", empleado.FirstName, empleado.LastName, empleado.Country);
El mapeo que realiza Dapper es la coincidencia del nombre del campo y del nombre de la propiedad de la clase. Si hay alguna propiedad que difiera de los campos de la clase, simplemente no lo mapeará.

Actualizaciones, inserciones y borrados
Para realizar operaciones de escritura usaremos los siguientes ejemplos:

Observa que se pueden ejecutar varias líneas dentro de la sentencia.
conn.Execute(@"set identity_insert employees on;
                insert into employees (EmployeeId, FirstName, LastName, Country) values (@EmployeeId, @FirstName, @LastName, @Country);
                set identity_insert employees off;"
                , new { FirstName = "Oswaldo", EmployeeId = 21, LastName = "Rodriguez", Country = "Cuba" });


conn.Execute("update employees set firstname=@FirstName where employeeId=@EmployeeId", new { FirstName = "Leopoldo", EmployeeId = 21 });

También se pueden realizar operaciones masivas pasando una lista de objetos.
var empleados = conn.Query>empleado<("select * from employees where country = @pais", new { @pais = "UK" });
foreach (var empleado in empleados)
     empleado.FirstName = "-" + empleado.FirstName;
conn.Execute("update employees set firstname=@FirstName where employeeId=@EmployeeId", empleados.Select(x=>new {FirstName=x.FirstName, EmployeeId=x.EmployeeId}));

Agregados
var sql="Select * from products p left join categories c on p.CategoryID=c.CategoryID";
var products = conn.Query>Producto, Categoria, Producto<(sql, (prod, cat) => { prod.categoria = cat; return prod; }, splitOn:"CategoryID");
Conclusiones
Como podéis ver, puede ser una buena alternativa para determinados proyectos.
Espero que os sea de utilidad.