VISITAS:

jueves, 25 de octubre de 2012

ANDROID: Ejercicios para crear layouts

Ejercicio 1

Fila de cuatro botones horizontalmente ocupando todo el ancho de la pantalla. Cada botón tiene que  ocupar el mismo espacio, o sea, el 25% del ancho de la pantalla.
Dejar un espacio alrededor del grupo de botones de 20dp. Separar entre sí cada uno de los botones por 5dp.


Solución


<LinearLayout 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:orientation="horizontal" android:padding="20dp">

  <Button android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_weight="1" android:layout_margin="5dp" android:text="Botón 1" />

  <Button android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_weight="1" android:layout_margin="5dp" android:text="Botón 2" />

  <Button android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_weight="1" android:layout_margin="5dp" android:text="Botón 3" />

  <Button android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_weight="1" android:layout_margin="5dp" android:text="Botón 4" />

</LinearLayout>

Explicación

Con un LinearLayout horizontal ponemos los 4 botones en  una fila.
El padding de 20dp en el LinearLayout pone un espacio interno para su contenido (los botones).
Cada botón tiene un weight de 1 para que sean todos iguales dentro del padre.
El margin de 5dp en los botones hace que éstos queden separados entre sí por 5dp. 

Ejercicio 2

Dividir la pantalla verticalmente en dos mitades. En la mitad superior superior, colocar una imagen que ocupe toda la parte superior. En la mitad inferior colocar un texto largo que permita desplazarse con scroll para poder visualizarlo.Ambas mitades deben estar rodeadas de un margen de 5dp.


Solución

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 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:orientation="vertical" android:padding="5dp">

  <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitCenter" android:layout_weight="1" android:src="@drawable/ic_launcher" />

  <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1">

    <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/texto" />

  </ScrollView>

</LinearLayout>

Ejercicio 3

Un botón que ocupe el 50% del ancho de la pantalla y que esté centrado vertical y horizontalmente en la pantalla.


Solución

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 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:orientation="horizontal" android:gravity="center" android:weightSum="100">

  <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="50" android:text="Botón" />

</LinearLayout>

Ejercicio 4

Construir el siguiente formulario:


Solución


<?xml version="1.0" encoding="utf-8"?>

<TableLayout 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:layout_marginTop="5dp" android:stretchColumns="1">

  <TableRow>

    <TextView android:text="Nombre (*)" android:layout_width="wrap_content" android:layout_height="wrap_content" />

    <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="6dp" />

  </TableRow>

  <TableRow>

    <TextView android:text="Apellido (*)" android:layout_width="wrap_content" android:layout_height="wrap_content" />

    <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="6dp" />

  </TableRow>

  <TableRow>

    <TextView android:text="e-mail (*)" android:layout_width="wrap_content" android:layout_height="wrap_content" />

    <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="6dp" />

  </TableRow>

  <TableRow>

    <TextView android:text="Mensaje" android:layout_width="wrap_content" android:layout_height="wrap_content" />

    <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="6dp" android:paddingRight="5dp" android:inputType="textMultiLine" android:lines="3" />

  </TableRow>

  <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">

    <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Suscribirse por e-mail" android:checked="true" />

  </LinearLayout>

  <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp">

    <TextView android:text="Web del vendedor" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#0000FF" android:textStyle="bold" />

  </LinearLayout>

  <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:gravity="center" android:orientation="horizontal">

    <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Confirmar" />

    <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Cancelar" />

  </LinearLayout>

</TableLayout>

lunes, 22 de octubre de 2012

ANDROID: Soporte para múltiples pantallas

Conceptos

  • Screen size (tamaño de pantalla): Es es tamaño físico de la pantalla, medido en pulgadas en su diagonal. Android agrupa todos los tamaños de pantalla en cuatro grupos: small, normal, large, extra-large.
  • Screen density (densidad de pantalla): Es la cantidad de pixels en un área física de la pantalla, dpi (dots per inch). Android agrupa las densidades de pantalla en cuatro grupos: low, medium, high y extra-high.
  • Orientation (orientación): Es la orientación de la pantalla desde el punto de vista del usuario. Puede ser landscape (paisaje, más ancho que alto) o portrait (retrato, más alto que ancho). La orientación puede cambiar en runtime cuando el usuario rota el dispositivo.
  • Resolution (resolución): Es el número total de pixels en la pantalla. Las aplicaciones no deberían tratar directamente con la resolución, sino con el tamaño de la pantalla y con la densidad de pixels (según los grupos de tamaños y resoluciones).
  • Density-independent pixels (dp, pixels independientes de la densidad): Es una unidad virtual de pixels que se usa cuando se definen layuts de UI. Se utiliza para expresar las dimensiones y/o posiciones de una forma independiente de la densidad. Un dp es equivalente a un pixel físico en una pantalla de 160 dpi, perteneciente al grupo de densidad medium. En runtime, el sistema maneja el escalado de los dp según sea necesario, para adaptarlos a la densidad real de la pantalla que se esté usando. La conversión de dp a pixels es muy sencilla: px = dp * dpi / 160. Siempre se deben utilizar dp cuando se definen las dimensiones y las posiciones en la UI para asegurar la visualización correcta en pantallas con diferentes densidades.

Rangos de pantallas soportados

Para simplificar el diseño de interfaces de usuario para múltiples tipos de pantallas, Android agrupa los rangos de tamaños y densidades de pantalla en:
  • Tamaños: small, normal, large, extra-large

  • Densidades: ldpi, mdpi, hdpi, xhdpi

La configuración base de pantalla es size=normal y density=medium.
Cuando se diseñan interfaces de usuario, se descubre que cada diseño requiere una cantidad mínima de espacio. Este tamaño mínimo se expresa en unidades dp.
Para optimizar una aplicación se suelen definir diferentes diseños para los diferentes tamaños y para las diferentes densidades. Normalmente se definen layouts alternativos para los distintos tamaños de pantalla (small, normal, large, xlarge) y bitmaps alternativos para las distintas densidades (ldpi, mdpi, hdpi, xhdpi). En runtime, Android utiliza los recursos más adecuados para cada caso.

Ejemplo: Múltiples densidades de pantalla

Imaginemos 3 dispositivos: A, B y C con las siguientes resoluciones y tamaños:
  • Dispositivo A: 6 x 8 pulgadas (diagonal = 10 pulgadas), 6 x 8 pixels. Este dispositivo tiene una densidad de 1 dpi
  • Dispositivo B: 6 x 8 pulgadas (diagonal = 10 pulgadas), 12 x 16 pixels. Este dispositivo tiene una densidad de 2 dpi
  • Dispositivo C: 6 x 8 pulgadas (diagonal = 10 pulgadas), 24 x 32 pixels. Este dispositivo tiene una densidad de 4 dpi
Los tres dispositivos tienen el mismo tamaño físico. Sin embargo, cada uno tiene una densidad de pixels distinta. El dispositivo A se podría considerar de baja densidad (ldpi), el B de densidad media (mdpi) y el C de alta densidad (hdpi). Nota: Esto es un ejemplo para comprender bien el problema con números pequeños; en la realidad una densidad media mdpi sería de unos 160 dpi.
Si ponemos un botón en la posición 0,0 de tamaño 4 x 4 pixels en cada uno de los dispositivos, obtendríamos los siguientes resultados:
  • En el dispositivo A, el botón ocuparía 4 x 4 pixels, o sea, 4 x 4 pulgadas.
  • En el dispositivo B, el botón ocuparía igualmente 4 x 4 pixels, pero en este caso serían 2 x 2 pulgadas, o sea, sería la mitad de grande que el mismo botón en el dispositivo A.
  • En el dispositivo C, el botón ocuparía los mismos 4 x 4 pixels, pero en este caso, el tamaño sería de 1 x 1 pulgada.
Como se puede observar, si expresamos el tamaño del  botón en pixels, tendremos un tamaño distinto en cada dispositivo, según la densidad de cada uno de estos. Siendo más grande cuanto menor es la densidad. Además, en cada caso, el espacio sobrante para otras vistas es distinto en cada dispositivo.

Vamos a colocar un botón en la posición 0,0 en los tres dispositivos. Pero ahora vamos a expresar el tamaño del botón en dp, no en pixels. Las dimensiones del botón serán 4 x 4 dp.
Antes de nada tenemos que definir la densidad de pixels de referencia (baseline). En los dispositivos android, esta densidad es de 160 dpi. Sin embargo en nuestro ejemplo vamos a considerar 2 dpi como la densidad de referencia. Entonces, si expresamos los tamaños en dp, el sistema android tendrá que calcular los pixels reales en función de la densidad de pixels del dispositivo. La fórmula, como vimos en el apartado anterior es: px = dp x dpi / 2
  • En el dispositivo A, el botón ocuparía 4 x 1 / 2 = 2 pixels, o sea, 2 pulgadas.
  • En el dispositivo B, el botón ocuparía 4 x 2 / 2 = 4 pixels, que también corresponden a 2 pulgadas.
  • En el dispositivo C, el botón ocuparía 4 x 4 / 2 = 8 pixels, 2 pulgadas igualmente.

Ahora el botón ocupa el mismo tamaño en todos los dispositivos y por tanto el espacio sobrante para otras vistas es lógicamente el mismo en todos los dispositivos.

Se considera que una aplicación es independiente de la densidad cuando preserva los tamaños físicos de los elementos de UI cuando se visualiza en pantallas de distintas densidades. Esta condición es muy importante, porque de no cumplirse, un elemento tal como un botón aparecerá más grande en pantallas de baja densidad y más pequeño en pantallas de alta densidad.

Como conclusión: Si expresamos las posiciones y tamaños en dp, resolvemos el problema que surge con dispositivos de distintas densidades de pixels.

Sin embargo, en el caso de los bitmaps, aunque expresemos su tamaño en dp, el sistema android intentará escalar el bitmap al tamaño físico adecuado. Pero este escalado a veces da como resultado imágenes borrosas y/o pixeladas. Esto se debe a que el escalado de un bitmap produce los siguientes efectos:

  • Ampliación: la imagen se pixela debido a que cada pixel de la imagen tiene que ocupar 2 o más pixels (dependiendo del factor de ampliación)
  • Reducción: la imagen se emborrona debido a que desaparecen pixels de la imagen (para reducir su tamaño)

Para evitar este problema con los bitmaps, es conveniente proporcionar una versión de cada bitmap para las distintas densidades. Se suele utilizar el siguiente criterio:

  • Bitmap para mdpi: 100%
  • Bitmap para hdpi: 150%
  • Bitmap para xhdpi: 200%
  • Bitmap para ldpi: 75%

Esto significa que si tenemos un bitmap de por ejemplo 100x100 pixels para mdpi, entonces deberíamos proporcionar otra versión del mismo bitmap a 150x150 pixels para hdpi, otra versión a 200x200 pixels para xhdpi y otra versión de 75x75 pixels para ldpi. Físicamente, todos se mostrarán con el mismo tamaño, pero no aparecerán los efectos de pixelado (en hdpi y xhdpi) ni de imagen borrosa (en ldpi).

El siguiente problema que se nos plantea es con dispositivos de distinto tamaño físico.

Soporte de múltiples tamaños y densidades de pantalla

Por defecto, Android renderiza el layout de la aplicación escalando bitmaps y layouts en función de la densidad y el tamaño de la pantalla. Sin embargo, esto puede no ser suficiente. A veces los programadores tienen que hacer algo también:

  • Declarar en el manifest los tamaños de pantalla que soporta la aplicación: de esta forma nos aseguramos que la aplicación sólo se ejecutará en los dispositivos con las pantallas soportadas. Para ello se utiliza el tag supports-screens  del fichero manifest.
  • Proporcionar diferentes layouts para diferentes tamaños de pantalla. Por defecto, Android re-escala el layout de la aplicación para encajarlo en el tamaño de pantalla actual. Esto funciona bien en algunos casos, pero no siempre. Por ejemplo, en una pantalla grande (como la de una tablet) suele ser interesante reorganizar los elementos aprovechando el mayor espacio disponible. Los layouts para los distintos tamaños de pantalla se colocan en los directorios: layout-small, layout-normal, layout-large, layout-xlarge
  • Proporcionar diferentes bitmaps para distintas densidades: Por defecto, Android escala los bitmaps de forma que tengan el tamaño deseado en función de la densidad del dispositivo. Por ejemplo, si sólo proporcionamos un bitmap para mdpi, cuando la aplicación se ejecute en hdpi, el sistema agrandará el bitmap. Y cuando se ejecute en ldpi, entonces el sistema reducirá el bitmap. Estos escalados pueden producir pixelado e imágenes borrosas. Para evitar estos fenómenos, lo mejor es proporcionar bitmaps para los distintos grupos de densidades. Estas versiones se colocarán en los directorios drawable-ldpi, drawable-mdpi, drawable-hdpi y drawable-xhdpi. Cuando no existe versión de un bitmap para una densidad determinada, el sistema busca la versión que más se acerque a la densidad del dispositivo actual.
El formato para los directorios de layouts y bitmaps es:

        resource-qualifier

El resource puede ser drawable o layout.
El qualifier puede ser:

  • Tamaño: small, normal, large, xlarge
  • Densidad: ldpi, mdpi, hdpi, xhdpi
  • Orientación: land, port
Los qualifiers se pueden concatenar con un guión. Por ejemplo, layout-small-port para un layout en pantallas de tamaño small y orientación portrait.
Si no se usa qualifier se supone que es para el  valor por defecto: normal y mdpi.

Diseño de layouts y drawables alternativos

Los tipos de recursos alternativos que se deberían crear dependen de las necesidades de la aplicación. Normalmente:
  • para los layouts se proporcionan los qualifiers para tamaño (small, normal, large, xlarge) y para orientación (land, port)
  • para los bitmaps se proporcionan los qualifiers para densidad (ldpi, mdpi, hdpi, xhdpi)

Layouts alternativos

Cuando se prueba la aplicación en diversos tamaños de pantalla y densidades es cuando se detecta la necesidad o no de proporcionar layouts alternativos. Por ejemplo:
  • Probando en una pantalla size=small, se descubre que  no caben todos los componentes (por ejemplo, una fila de botones). En este caso se debería proporcionar un layout para pantallas small que ajuste el tamaño y/o posición de los botones.
  • Probando en una pantalla size=xlarge, se descubre que sobra mucho espacio. En este caso se debería proporcionar un layout para pantallas xlarge con un rediseño de los componentes para aprovechar el espacio en una pantalla grande. Si dejamos que el sistema redimensione los componentes para adaptarse a una pantalla grande, el usuario tendrá una mala experiencia con la aplicación. Es mucho mejor hacer un diseño especial para pantallas grandes.
  • Probando en orientation=land, se descubre que algunos elementos que estaban en la parte inferior de la pantalla no aparecen.
En resumen, hay que diesñar para size=normal, y luego probar la aplicación en:
  • size=small
  • size=large
  • orientation=land
  • orientation=port

Drawables alternativos

Todas las aplicaciones deberían tener drawables alternativos para las diferentes densidades. El drawable más importante es el icono launcher, que debe mostrarse perfectamente en todas las densidades.
Los bitmaps deberían seguir las siguientes escalas:

ldpi > mdpi > hdpi > xhdpi
3 > 4 > 6 > 8
75% > 100% > 150% > 200%

Consejos y buenas prácticas

El objetivo de soportar múltiples pantallas es crear aplicaciones que funcionen adecuadamente en todos los grupos de tamaños, orientaciones y densidades que soporta Android.

1. Usar wrap_content, match_parent o dp para dimensiones

Se deben utilizar estos valores para los atributos layout_width y layout_height
Igualmente, se debe utilizar dp para el tamaño de los textos.

2. No usar pixels en el código de la aplicación

Los métodos del API de Android que obtienen dimensiones y posiciones retornan los valores en pixels.

3. No utilizar AbsoluteLayout

AbsoluteLayout obliga a utilizar posiciones fijas en las vistas hijas, lo cual provocará que las aplicaciones no funcionen en múltiples configuraciones de pantallas.
Se debería utilizar RelativeLayout, el cual usa posiciones relativas para colocar a sus vistas hijas.



viernes, 19 de octubre de 2012

ANDROID: Layouts

Los layouts de Android son los contenedores.
Un layout contiene hijos que pueden ser vistas o bien otros contenedores, formando así una jerarquía de componentes.
Existen varios tipos de layout que pasamos a describir.

FrameLayout

Muestra todas sus vistas hijas una encima de otra.
Las vistas se colocan una encima de otra según el orden en que se van añadiendo al layout (la última vista añadida es la que se muestra arriba del todo).

TableLayout

Organiza las vistas hijas en en filas y columnas. Cada fila es un contenedor de tipo TableRow.
El número de columnas será igual al número de celdas del TableRow con más celdas.
Las vistas hijas no pueden especificar layout_width.
Las celdas pueden abarcar varias columnas.

LinearLayout

Organiza las vistas hijas en una fila horizontal o vertical, según el atributo:
  • orientation
Las vistas hijas especifican cuánto espacio ocupan con el atributo:
  • layout_weight (peso)
especificando un peso relativo respecto a las demás vistas hijas.
Cuando layout_weight = 0 entonces la vista hija ocupa el espacio necesario según su contenido.
Por defecto, todas las vistas tienen el mismo peso con valor cero y ocuparán el espacio necesario según su contenido.
El comportamiento es el siguiente: las vistas con layout_weight = 0 ocupan el espacio que necesitan según su contenido; el resto de vistas con layout_weight > 0 se reparten el espacio restante proporcionalmente al valor de layout_weight.
Si una vista tiene layout_weight > 0 entonces hay que poner layout_width = 0 y layout_height = 0 para evitar problemas.

RelativeLayout

Organiza sus vistas hijas según su posición relativa a otras vistas y al propio layout.
Atributos de las vistas para alinear con el layout padre:
  • layout_alignParentTop, Bottom, Left, Right: true o false
Atributos de las vistas para centrar en el layout padre:
  • layout_centerHorizontal, Vertical, InParent: true o false
Atributos de las vistas para alinear con otras vistas en el mismo layout:
  • layout_alignTop, Bottom, Left, Right: id de la otra vista
Atributos de las vistas para ponerse en el mismo lugar que otra vista (overlap):
  • layout_alignBaseline: id de la otra vista
Atributos de las vistas para situarse junto a otra vista:
  • layout_above, below, leftOf, rightOf: id de la otra vista
Todos estos atributos se aplican según el orden de creación de las vistas dentro del layout.

ANDROID: Atributos para posicionar las vistas

Las vistas representan áreas en la pantalla: botón, texto, imagen.
Las vistas se organizan dentro de los contenedores, formando una jerarquía de contenedores y vistas.

Ancho y Alto

El ancho y alto de una vista y/o contenedor se definen con los atributos:
  • layout_width
  • layout_height
Los valores posibles para estos atributos son:
  • valor exacto (se recomienda utilizar dp)
  • wrap_content: para que la vista se expanda al tamaño según su contenido
  • match_parent: para que la vista se expanda para ocupar todo el tamaño del contenedor padre

Margen y Padding

Se utilizan los atributos:
  • layout_margin
  • padding
El margen crea espacio fuera de la vista, separándola del resto de vistas.
El padding crea espacio dentro de la vista.
Margen y padding se pueden especificar para cada lado.

Gravity

Por defecto, los contenedores colocan a sus hijos a la izquierda (gravity = left). Pero esto se puede cambiar, tanto en los contenedores como en las vistas hijas.
Atributos:
  • gravity: Se usa en los contenedores e indica la posición por defecto para los hijos. En una vista indica cómo se alineará el contenido de la vista
  • layout_gravity: Se usa en los hijos e indica la posición de un hijo en el padre.
Por ejemplo, supongamos un TextView con layout_width = "match_parent". En este caso, el texto ocupará el ancho de su padre, pero el texto saldrá alineado a la izquierda. Si queremos el texto centrado, tendremos que poner gravity = "center" en el hijo.
Si el TextView tiene layout_width = "wrap_content" y queremos que el texto salga centrado, entonces tendremos que poner layout_width = "center" para que la vista se centre en su padre, y por tanto, el texto salga centrado.
En el caso de IamgeView, no tiene el atributo gravity, entonces lo mejor es envolverlo en un LinearLayout y ponerle la gravity deseada.

ANDROID: Resoluciones, pixels, densidad...

Resoluciones típicas

Android define las siguientes resoluciones de pantalla típicas:
  • QVGA: 240 x 320 pixels
  • HVGA: 320 x 480 pixels
  • WQVGA: 240 x 432 pixels
  • WVGA: 480 x 800 pixels
  • WXGA: 1280 x 800 pixels
La densidad de pixels de un dispositivo es el número de pixels por pulgada física de pantalla (dpi).
¿Cómo calcular la densidad de pixels de un dispositivo? Normalmente conocemos la resolución horizontal y vertical en pixels, además del tamaño de la pantalla en pulgadas (diagonal).
Sean:
h = resolución horizontal en pixels
v = resolución vertical en pixels
i = diagonal en pulgadas
A partir de estos datos podemos calcular la densidad de pixels por pulgada de la siguiente forma:

dpi = sqrt( h * h + v * v) / i

Por ejemplo, w=1280 pixels, h=800 pixels, i = 10.1 pulgadas.
dpi = sqrt( 1280 * 1280 + 800 * 800) / 10.1 = 149 dpi

Tamaños de pantalla

Android define los siguientes tamaños de pantalla (son valores aproximados):
  • small: desde 2 pulgadas a 3 pulgadas
  • normal: desde 3 pulgadas a 4.5 pulgadas
  • large: desde 4.5 pulgadas hasta 7 pulgadas
  • xlarge: desde 7 pulgadas hasta 10 pulgadas

Densidades de pantalla

Android define las siguientes densidades:
  • ldpi: desde 100 hasta 150
  • mdpi: desde 150 hasta 200
  • hdpi: desde 200 hasta 250
  • xhdpi: desde 250 hasta 300

Programación para varias densidades de pantalla

Las distintas densidades siguen las siguientes proporciones aproximadamente: 3 : 4 : 6 : 8
Así, si tenemos un bitmap de 100x100 pixels para mdpi, deberíamos tener las versiones del bitmap siguientes:
  • 75x75 para ldpi
  • 150x150 para hdpi
  • 200x200 para xhdpi
Y de esta forma, el bitmap saldrá con el mismo tamaño real en todas las densidades de pantalla.
Cuando se programa para Android, siempre se deben especificar los tamaños en dp (density pixels). 1 dp es un pixel en una pantalla mdpi de 160 dpi.
Si especificamos los tamaños en dp, entonces Android convierte los dp a pixels aplicando la siguiente fórmula:
pixels = dp * dpi / 160
Si por ejemplo, un botón tiene un ancho de 100 dp, entonces en una pantalla de 200 dpi Android le dará un tamaño de 100 * 200 / 160 = 125 pixels. Sin embargo, en una pantalla de 100 dpi, Android le dará un tamaño de 100 * 100 / 160 = 62 pixels. El tamaño visual será siempre el mismo.
Se recomienda que los objetos que puede pulsar el usuario con el dedo tengan un tamaño de al menos 45x45 dp.

martes, 17 de abril de 2012

Expresiones Regulares (II)

Las expresiones regulares (RE) son un lenguaje estándar para especificar búsquedas en un texto.
Se utilizan en muchas herramientas Unix como vi, emacs, greps, etc así como en Microsoft Word, por ejemplo. Pero además de este uso práctico, las expresiones regulares también se utilizan como una herramienta teórica en lingüística computacional.
Las expresiones regulares son "case sensitive" (las mayúsculas son distintas de las minúsculas). Si se busca /agua/ no se encontrarán cadenas como "Agua".
Los corchetes permiten uno entre varios caracteres. Si se busca /[Aa]gua/ se encontrarán cadenas como "agua" y "Agua". Los corchetes permiten especificar rangos de caracteres, como en /[1-0]/ para buscar un dígito, o /[A-Z]/ para encontrar una letra mayúscula. El símbolo ^ al principio de unos corchetes indica un patrón que no se debe cumplir, por ejemplo, /[^A-Z]/ busca cualquier carácter que no sea una letra mayúscula, /[^sS]/ cualquier carácter que no sea la "s" (mayúscula o minúscula). Si el carácter ^ aparece en otro lugar que no sea inmediatamente después del corchete, entonces significa buscar el propio carácter ^, no una negación.
La interrogación ? hace que un carácter sea opcional. Si se busca /colou?r/ encontrará las cadenas "colour" y "color", /casas?/ encontrará las cadenas "casa" y "casas". La interrogación convierte en opcional el carácter inmediatamente anterior.
El símbolo * es parecido al símbolo ?, permite buscar el carácter anterior repetido cualquier número de veces (o ninguna). Si se busca /ca*sa/ se encontrarán cadenas como "csa" "casa" "caasa" "caaasa", etc.
El símbolo + es parecido al símbolo ?, permite buscar el carácter anterior al menos una vez y repetido cualquier número de veces. Si se busca /ca+sa/ se encontrarán cadenas como "casa" "caasa" "caaasa", etc.
El símbolo . se puede sustituir por cualquier carácter. Si se busca /pep./ se encontrarán cadenas como "pepa" "pepe" "pepi" etc.
El símbolo | permite hacer un OR entre varias cadenas de caracteres. Por ejemplo, /casa|house/ buscará las cadenas "casa" y "house".
Para encontrar cadenas al principio o al final de una línea, se utilizan los símbolos ^ y $. Si se busca /^La/ se encontrarán líneas que comiencen por "La". Si se busca /.$/ se encontrarán las líneas que terminen con .
Si se quiere buscar exactamente un símbolo como *, ?, etc se usará: /\*/ /\?/ /\./ /\+/



martes, 7 de febrero de 2012

Tecnologías de localización y posicionamiento en móviles

Veamos primero un ejemplo. Hemos desarrollado una aplicación para móvil que utiliza localización por GPS y muestra continuamente la posición actual, por ejemplo en un mapa.
Un usuario descarga e instala la aplicación en su móvil, la activa y se olvida de ella durante 30 minutos. Después de ese tiempo, el usuario se da cuenta de que el teléfono le está avisando que la batería está a punto de acabarse. No es una experiencia agradable...
Una solución rápida a este problema es utilizar el Cell ID como mecanismo de posicionamiento, cambiando puntualmente a GPS si se requiere. Esto permitiría alargar considerablemente la duración de la batería.
Existen varias tecnologías para conseguir la localización:
  • triangulación de celdas
  • satélites (GPS)
  • identificador de celda (Cell ID)
  • Wi-Fi (WPS)
  • Posicionamiento híbrido
El desarrollador de aplicaciones debe decidir qué método o combinación de métodos es el más adecuado para cada aplicación, haciendo un balance entre exactitud de la localización y otros factores como consumo de batería y velocidad de localización.

¿Qué son las tecnologías de localización?
Las tecnologías de localización en los móviles permiten conocer dónde se encuentra el dispositivo en un momento dado (con diferentes grados de exactitud). Estas tecnologías son una combinación de hardware (antenas GPS por ejemplo) y software (cálculo de triangulaciones en función de la señal recibida de distintas antenas GSM). Cada una de estas tecnologías tienen unas ventajas y unos inconvenientes, en términos de exactitud, velocidad de localización y consumo de batería, entre otros.

Triangulación de Celdas
Esta tecnología se basa en los niveles de señal recibidos por el móvil de las torres o celdas cercanas, calculando en función de esto la distancia aproximada a cada una de las torres desde las que se recibe señal.
Por geometría teórica, si se conoce la distancia a tres puntos distintos (de posición conocida), es posible conocer la localización del punto actual. Si se tienen cuatro puntos distintos, la localización mejora. La precisión mejora aún más cuando además de la distancia se conoce la dirección de donde proviene la señal.
En zonas urbanas, donde hay una mayor densidad de torres cercanas, la precisión es de alrededor de 200 metros.
En zonas rurales, donde a veces sólo disponemos de la señal de una torre, la precisión empeora considerablemente, llegando a ser del orden de kilómetros.
El principal problema de esta tecnología, además de la precisión en zonas rurales, es que la legislación en muchos países no obliga a las operadoras a informar del nivel de señal de las torres, con lo cual no se puede calcular la distancia a la torre.
Por este motivo, se utilizan más frecuentemente las demás tecnologías.

Navegación GPS
Esta tecnología es actualmente la más precisa de todas, con valores de 4 metros (como mucho).
Además, esta tecnología es gratuita para el usuario final.
Existen dos variantes de esta tecnología:
  • GPS estándar
  • A-GPS (GPS asistido)
El GPS estándar utiliza 31 satélites que están orbitando alrededor de la Tierra. La localización del dispositivo se determina calculando las diferencias de las señales de tiempo (reloj) provenientes de diferentes satélites.
Los receptores GPS reciben y analizan continuamente la señal recibida de los satélites GPS, calculando la distancia a cada uno de los satélites visibles. La distancia se calcula teniendo en cuenta la velocidad del satélite orbitando y el tiempo que tarda su señal en llegar a la Tierra.
Teniendo en cuenta sólo la señal de un satélite, se puede restringir la posición del dispositivo a un área relativamente grande de la superficie terrestre (círculo). Si añadimos la señal proveniente de un segundo satélite, tenemos otro círculo, y podemos reducir el área efectiva a la intersección de los dos círculos. Con un tercer satélite se puede conseguir una posición bastante precisa. Añadiendo la señal de un cuarto satélite se puede conseguir incluso la información de la altura.
Actualmente, los dispositivos reciben señal de 7 o más satélites continuamente.
Si el receptor no es capaz de recibir la señal de un número mínimo de satélites, entonces no podrá localizar la posición del dispositivo.
La principal ventaja del GPS estándar es su precisión: unos 4 metros, con una visión clara del cielo, hasta 40 metros en lugares con poca visibilidad.
Pero tiene una serie de desventajas muy a tener en cuenta: el consumo de batería es muy alto y necesita un tiempo considerable para conseguir la primera localización (aunque una vez localizado, las siguientes localizaciones son rápidas). También tiene el problema en las zonas urbanas de zonas de poca o nula visibilidad del cielo (por ejemplo en túneles).
El tiempo para fijar la primera localización se denomina Time To First Fix (TTFF) o también llamado "arranque en frío". En receptores como el último SiRF III lleva entre 30 segundos y dos minutos.

El GPS asistido (A-GPS) es una solución que mejora la "fiabilidad" del GPS estándar.
No existe una definición precisa de A-GPS, ya que depende del fabricante del receptor, el operador, e incluso de la legislación en cada país. Pero básicamente, A-GPS intenta resolver el problema del GPS estándar donde no es posible localizar en lugares difíciles (con poca visibilidad del cielo). El objetivo es ayudar al GPS estándar a conseguir una localización más rápida y/o más precisa en entornos complicados (tales como señal débil del GPS o visibilidad de sólo dos satélites).
En un dispositivo con A-GPS el TTFF es mucho más rápido que con GPS estándar.
Las torres de la red móvil tienen un receptor GPS que está continuamente "visualizando" satélites en el cielo. Esta información sobre los satélites visibles en la zona se envía al dispositivo móvil y evita tener que sondear a todos los posibles satélites, centrándose sólo en los que le indica la torre, permitiendo así un arranque o TTFF mucho más rápido (y un ahorro considerable de batería).
La desventaja de A-GPS es que depende de que el operador envíe o no estos datos al dispositivo, y además se incurre en una transferencia de datos, con los posibles costes para el usuario. Además, como se puede intuir de estas explicaciones, para que funcione el A-GPS debemos tener activada la red de datos.

Cell ID
Cell ID es la tecnología que precisa de un menor consumo de energía. Se basa en la información sobre la celda o torre a la cual está conectada el dispositivo móvil. La posición de esta torre es conocida. Además, cada celda en el mundo tiene un identificador único e irrepetible (Cell ID). La ITU asigna a cada operador un rango de identificadores que luego éste asigna individualmente a cada celda.
Evidentemente, la precisión de este método depende del tamaño de la celda a la que estamos conectados, es decir, en zonas urbanas donde hay muchas antenas el tamaño de la celda es pequeño y por tanto, la precisión es mejor. Hay que tener en cuenta que el tamaño de una celda GSM puede llegar a los 18 kilómetros de radio, aunque lo normal es entre 1 y 2 kilómetros.

WPS
El posicionamiento por Wi-Fi (WPS) es relativamente nuevo y novedoso. La principal ventaja de WPS es que funciona en lugares cubiertos, donde el GPS no puede funcionar.
Esta tecnología se basa en que los routers Wi-Fi emiten una señal con su posición. El dispositivo escanea las redes Wi-Fi cercanas (no es necesario conectarse a ellas, y por tanto, no es necesario conocer la password de acceso a estas redes). Entonces calcula la posición del dispositivo utilizando un mecanismo similar a la triangulación por celdas explicado anteriormente. Con la diferencia de que ahora no dependemos de la emisión de los datos de posición de la celda, ya que los routers Wi-Fi emiten estos datos "gratuitamente".
Y ahora la gran pregunta: ¿Cómo sabe un router Wi-Fi su posición? Un router Wi-Fi no tiene receptor GPS y aunque lo tuviera, es difícil que pudiera localizarse por encontrarse habitualmente en lugares cerrados.
La respuesta a esta pregunta no es obvia. La empresa norteamericana Skyhook Wireless desarrolla una base de datos de routers Wi-Fi con el id de cada router y su posición. Pero ¿cómo? ¿Cómo conoce esta empresa la posición de, por ejemplo, el router de mi casa? Pues simplemente recorriendo las ciudades del mundo con vehículos que van escaneando las redes Wi-Fi y anotando la posición y el id del router. De esta forma van construyendo una base de datos con todos los routers (actualmente con más de 100 millones de routers).
A partir de estos datos, el dispositivo sólo tiene que escanear las redes Wi-Fi cercanas y a partir de los id de los routers buscar la posición de los mismos en la base de datos de Skyhook y triangular.

Posicionamiento Híbrido
El posicionamiento híbrido es una tecnología que combina todas o alguna de las tecnologías descritas anteriormente para localizar el dispositivo intentando una buena precisión, bajo consumo de batería y bajo TTFF. Este mecanismo se utiliza habitualmente en los dispositivos Android e iPhone.












martes, 24 de enero de 2012

Servicios Web con .NET (howto)

En este artículo describiré paso a paso cómo crear un servicio web con .NET desde cero.
Las versiones que utilizaré son:
  • Windows 7
  • IIS 7.5
  • Visual Studio 2010
CREAR UNA SOLUCIÓN
1. Crear un directorio base, por ej, D:\apps\Calculadora
2. Abrir VisualStudio
3. New Project > Other Project Types > Visual Studio Solutions > Blank Solution
Name: CalculadoraSolution
Location: directorio base
OK
Visual Studio crea un subdirectorio para la solución D:\apps\Calculadora\CalculadoraSolution

PROYECTO PARA EL WS
1. Solution Explorer > Botón derecho sobre la solución > Add > New Project
2. Visual Basic > Web > ASP.NET Web Service Application
Name: CalculadoraWS
Location: Subdirectorio de la solución (...CalculadoraSolution)
OK
Visual Studio crea un subdirectorio para el proyecto D:\apps\Calculadora\CalculadoraSolution\CalculadoraWS
3. Solution Explorer > Botón derecho sobre Service1.asmx > Rename
Cambiar el nombre a CalculadoraService.asmx
4. Cambiar el nombre de la clase
Solution Explorer > Botón derecho sobre el fichero CalculadoraService.asmx > View Code
Botón derecho sobre la clase Service1 > Rename
Cambiar el nombre a Calculadora
Si se desea, se puede cambiar también el atributo Namespace
Solution Explorer > Botón derecho sobre el fichero CalculadoraService.asmx > View Markup
En el atributo Class, poner: CalculadoraWS.Calculadora
5. Meter las operaciones:
Solution Explorer > Botón derecho sobre el fichero CalculadoraService.asmx > View Code
Quitar el método HelloWorld y añadir los siguientes métodos:
Public Function Suma(ByVal a As Double, ByVal b As Double) As Double
Return a + b
End Function

Public Function Resta(ByVal a As Double, ByVal b As Double) As Double
Return a - b
End Function

6. Build > Build Solution

DESPLEGAR EN IIS
1. Abrir el administrador de IIS: Panel de Control > Herramientas administrativas > Administrador de Internet Information Services (IIS)
2. Crear el directorio D:\apps\Calculadora\WWW
3. Botón derecho sobre Sitios > Agregar Sitio Web
Nombre del sitio: Calculadora
Ruta de acceso física: D:\apps\Calculadora\WWW
Puerto: 82
Aceptar
4. Botón derecho sobre el sitio Calculadora > Agregar aplicación
Alias: CalculadoraApp
Ruta: directorio del proyecto, D:\apps\Calculadora\CalculadoraSolution\CalculadoraWS
Aceptar
5. Abrir un navegador (Internet Explorer)
6. Invocar una operación
Pulsar sobre el enlace Suma
Introducir valores para los parámetros a y b
Pulsar el botón Invocar
El resultado será el mensaje XML devuelto por el servicio

CLIENTE .NET
1. Solution Explorer > Botón derecho sobre la solución > Add > New Project
2. Visual Basic > Windows > Windows Forms Application
Name: CalculadoraClient
Location: Subdirectorio de la solución (...CalculadoraSolution)
OK
Visual Studio crea un subdirectorio para el proyecto D:\apps\Calculadora\CalculadoraSolution\CalculadoraClient
3. Añadir dos TextBox al formulario para los parámetros a y b
4. Añadir un Label al formualrio para poner el resultado
5. Añadir dos Button al formulario para invocar las operaciones suma y resta
6. Solution Explorer > Proyecto Calculadora Client > Add Web Reference
Pulsar la flecha verde
Web reference name: calculadoraws
Botón Add Reference
7. En el callback de los botones hay que invocar a las operaciones del servicio
Dim a As Double = CDbl(txtA.Text)
Dim b As Double = CDbl(txtB.Text)
Dim calc As calculadoraws.Calculadora = New calculadoraws.Calculadora
Dim res As Double = calc.Suma(a, b)
lblResultado.Text = CStr(res)
8. Solution Explorer > Proyecto CalculadoraClient > Set as startup project
9. Debug > Start debugging

LIBRERÍA PARA LA LÓGICA Y CÁLCULOS
Imaginemos ahora que queremos separar el servicio web de la lógica (cálculos en este caso). Nos interesa hacer una librería para meter allí toda la lógica, e invocar a esta librería desde el servicio.

1. Solution Explorer > Botón derecho sobre la solución > Add > New Project
2. Visual Basic > Windows > Class Library
Name: CalculadoraLib
Location: Subdirectorio de la solución (...CalculadoraSolution)
OK
Visual Studio crea un subdirectorio para el proyecto D:\apps\Calculadora\CalculadoraSolution\CalculadoraLib
3. Solution Explorer > Botón derecho sobre el fichero Class1.vb
Rename
Renombrar a CalculadoraLib.vb
4. Implementar los métodos de la clase:
Public Function Suma(ByVal a As Double, ByVal b As Double) As Double
Return a + b
End Function

Public Function Resta(ByVal a As Double, ByVal b As Double) As Double
Return a - b
End Function
5. Build > Build Solution
6. Solution Explorer > Botón derecho sobre el proyecto CalculadoraWS > Add Reference
Seleccionar el proyecto CalculadoraLib
Cada vez que se reconstruya el proyecto, Visual Studio copiará el fichero CalculadoraLib.dll en el directorio bin del proyecto CalculadoraWS
7. Cambiar la implementación del servicio web para que invoque a la librería:

Public Function Suma(ByVal a As Double, ByVal b As Double) As Double
Dim calc As CalculadoraLib.CalculadoraLib = New CalculadoraLib.CalculadoraLib
Return calc.Suma(a, b)
'Return a + b
End Function

Public Function Resta(ByVal a As Double, ByVal b As Double) As Double
Dim calc As CalculadoraLib.CalculadoraLib = New CalculadoraLib.CalculadoraLib
Return calc.Resta(a, b)
' Return a - b
End Function

Aunque parezca que hemos complicado el código, en realidad lo hemos simplificado muchísimo, ya que la lógica y los cálculos suelen ser bastante complicados, y es bueno mantenerlos en una librería aparte.

8. Probar de nuevo el servicio invocando la URL: http://localhost:82/CalculadoraApp/CalculadoraService.asmx

TIPOS COMPLEJOS
A veces es necesario pasar como entrada o como salida tipos de datos complejos.
1. Solution Explorer > Botón derecho sobre el proyecto CalculadoraLib > Add > Class
Common items > Code > Class
Name: DatosCalculadora.vb
OK
2. Este es el contenido del nuevo fichero:
Public Class Entrada

Public a As Double
Public b As Double

End Class

Public Class Salida

Public suma As Double
Public resta As Double

End Class

3. Añadir una nueva función a CalculadoraLib.vb:
Public Function SumaResta(ByVal ent As Entrada) As Salida
Dim sal As Salida = New Salida
sal.suma = Suma(ent.a, ent.b)
sal.resta = Resta(ent.a, ent.b)
Return sal
End Function

4. Build > Build Solution
5. Añadir una nueva operación al servicio en CalculadoraService.asmx.vb
Public Function SumaResta(ByVal ent As CalculadoraLib.Entrada) As CalculadoraLib.Salida
Dim calc As CalculadoraLib.CalculadoraLib = New CalculadoraLib.CalculadoraLib
Return calc.SumaResta(ent)
End Function

6. Build > Build Solution
Si se pulsa sobre la nueva operación SumaResta no podremos probarla ya que tiene tipos compuestos

8. Solution Explorer > Botón derecho sobre calculadoraws (Web reference) del proyecto CalculadoraClient > Update Web Reference
9. En el formulario de CalculadoraClient meter un nuevo botón para SumaResta
10. En el callback del nuevo botón poner:
Private Sub btnSumaResta_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSumaResta.Click
Dim a As Double = CDbl(txtA.Text)
Dim b As Double = CDbl(txtB.Text)
Dim calc As calculadoraws.Calculadora = New calculadoraws.Calculadora
Dim ent As calculadoraws.Entrada = New calculadoraws.Entrada
ent.a = a
ent.b = b
Dim sal As calculadoraws.Salida = calc.SumaResta(ent)
lblResultado.Text = "Suma = " & sal.suma & ", resta = " & sal.resta
End Sub

11. Debug > Start debugging


lunes, 23 de enero de 2012

Introducción al procesamiento del lenguaje natural (I)

Empiezo con éste, una serie de artículos sobre procesamiento del lenguaje natural. Este es el primero que servirá de introducción. Trataré temas como análisis de palabras (autómatas, expresiones regulares, transductores, N-gramas, part-of-speech tagging, modelos de Markov), análisis sintáctico (gramáticas formales, parseado sintáctico, parseado estadístico, unificación) y análisis semántico (representación del significado, semántica computacional, semántica léxica, semántica léxica computacional, discurso).
Si todo va bien, serán muchos artículos durante bastante tiempo. Empecemos por tanto introduciendo el procesamiento del lenguaje natural (NLP) con sistemas informáticos.

La idea de dar a los ordenadores la capacidad de procesar el lenguaje humano no es nueva. Se trata de un campo interdisciplinar que abarca: estadística, computación, almacenamiento masivo, teoría de la información, aprendizaje automático, lingüística computacional, etc. El objetivo de este campo es conseguir que los ordenadores ejecuten tareas útiles que involucran al lenguaje humano. Ejemplos de sistemas o aplicaciones serían: agentes conversacionales, traducción automática, respuesta a preguntas, extracción de información, chequeo ortográfico y gramatical, reconocimiento de voz, generación automática de texto, etc.

CONOCIMIENTOS UTILIZADOS EN NLP
La principal diferencia entre NLP y otras aplicaciones de proceso de datos es que NLP utiliza conocimientos del lenguaje. Estos conocimientos del lenguaje se pueden resumir en:
  • Fonética y fonología: conocimiento sobre los sonidos. Cómo se pronuncian las palabras en términos de secuencias de sonidos y cómo estos sonidos se generan acústicamente.
  • Morfología: conocimiento de los componentes de cada palabra. Cómo se forma el plural, las distintas personas y tiempos verbales.
  • Sintaxis: conocimiento de las relaciones estructurales entre las palabras de una frase. No todas las secuencias de palabras son válidas, existen unas reglas que hay que cumplir. Además, intercambiar el orden de ciertas palabras, puede cambiar completamente el significado de una frase.
  • Semántica: Conocimiento del significado de cada palabra.
  • Pragmática: Conocimiento sobre cómo el contexto influye en el significado.
  • Discurso: Conocimiento sobre unidades lingüísticas más grandes que una frase. Es decir, cómo afecta lo que se ha dicho en frases anteriores al significado de la frase actual.

AMBIGÜEDAD
Un aspecto común a todos los conocimientos utilizados en NLP (fonética, fonología, morfología, sintaxis, semántica, pragmática y discurso) es que todos intentan resolver ambigüedades.
Los modelos y algoritmos del NLP presentan diversas formas de resolver estas ambigüedades.

MODELOS Y ALGORITMOS
Afortunadamente, todas las clases de conocimiento mencionadas pueden ser capturadas utilizando un número relativamente pequeño de modelos y teorías. Además estos modelos son conocidos sobradamente en la ciencia informática.
Los modelos más importantes son: máquinas de estados, sistemas de reglas, lógica, modelos probabilísticos y modelos espacio-vectoriales. Estos modelos llevan a una serie de algoritmos que se utilizarán para implementar aplicaciones NLP. Veamos rápidamente cada unos de estos modelos.
Las máquinas de estados son modelos formales que consisten en estados, transiciones entre estados y entradas (eventos). Se utilizan en fonología, morfología y sintaxis.
Los sistemas de reglas son gramáticas (regulares o libres de contexto). Se utilizan en fonología, morfología y sintaxis.
Los modelos basados en lógica (de primer orden o de predicados) se han utilizado habitualmente para modelar semántica y pragmática.
Los modelos probabilísticos se pueden utilizar para mejorar las cualidades de todos los demás modelos (máquinas de estados, reglas, lógica). La ventaja de los modelos probabilísticos es su capacidad para resolver muchos problemas de ambigüedad dando una probabilidad a cada una de las soluciones posibles.
Finalmente, los modelos espacio-vectoriales están basados en el álgebra lineal y se utilizan en el tratamiento del significado de las palabras.

En cualquiera de estos modelos, el procesamiento del lenguaje implica buscar en un espacio de estados que representan hipótesis sobre una entrada. Por ejemplo, en reconocimiento de voz, se busca en un espacio de secuencias de sonidos para encontrar la palabra correcta. En análisis sintáctico, se busca en un espacio de árboles sintácticos.

LENGUAJE, IDEAS Y COMPRENSIÓN
Muchos expertos opinan que cuando la capacidad de los ordenadores para procesar el lenguaje sea comparable a la que tenemos los humanos, eso será señal de que las máquinas son realmente inteligentes. Esta creencia se basa en el hecho de que el uso efectivo del lenguaje está directamente relacionada con nuestras habilidades cognitivas.
Turing en 1950 propuso la siguiente prueba. Tres participantes, dos personas y un ordenador. Una de las personas, el entrevistador, habla con dos terminales. Detrás de uno de ellos está la otra persona y tras el otro está el ordenador. Para ganar, el entrevistador debe adivinar detrás de qué terminal está el ordenador. La persona tras el terminal debe convencer al entrevistador que él es el humano. El ordenador tratará de engañar al entrevistador para que llegue a creer que él es realmente humano. El tiempo de la entrevista es de cinco minutos.
Afortunadamente, para los propósitos y objetivos del NLP, no es importante si el ordenador es inteligente o no.

ESTADO DEL ARTE
Estamos en un momento en que el NLP puede ser algo apasionante. Los recursos de computación y almacenamiento son muy baratos y podríamos decir que casi ilimitados, incluso para un usuario medio. La web es una fuente de información masiva que crece día a día.
Estos son ejemplos de aplicaciones funcionando hoy día que reflejan esta tendencia:
  • Reserva de viajes con agentes conversacionales
  • Sistemas de navegación GPS que reconocen las indicaciones de voz del conductor
  • Sistemas de búsqueda en vídeos que analizan millones de grabaciones de audio por reconocimiento de voz
  • Buscadores multilenguaje (Google)
  • Analizadores automáticos de artículos
  • Agentes virtuales que enseñan a los niños, por ejemplo a leer
  • Análisis de opiniones de usuarios en blogs, foros y grupos de usuarios







viernes, 20 de enero de 2012

Segmentación de sentencias (5)

En la mayoría de los lenguajes escritos, las sentencias se separan con los signos de puntuación. A pesar de ello, las reglas de puntuación no siempre están definidas claramente y además, no siempre se siguen estrictamente.
Además, en función del idioma, se utilizan distintos signos de puntuación para delimitar las sentencias y subsentencias. Por ejemplo, el español comienza las sentencias interrogativas con el signo ¿, mientras que el inglés no.
Parece que en general, el problema de la segmentación de sentencias es un problema de menor dificultad que el de la segmentación de palabras o tokenización.
Los signos de puntuación más utilizados son el punto, la coma, la interrogación, la exclamación, el punto y coma, los dos puntos.
Sin embargo, un punto puede utilizarse también como separador decimal en un número (o separador de miles, dependiendo del idioma), o como fin de una abreviatura, o incluso como una abreviatura al final de una sentencia. Los puntos suspensivos se pueden utilizar para terminar una sentencia, pero también en mitad de una sentencia. También a veces un paréntesis delimita una sentencia.
Por tanto, no podemos considerar el problema de la segmentación de sentencias como un problema trivial de fácil resolución, ni mucho menos.
Veamos ahora las técnicas que se pueden aplicar para resolver este problema.
Segmentación de sentencias con signos de puntuación
La mayoría de las aplicaciones NLP utilizan el punto, la interrogación y la exclamación como separadores de sentencias, definiéndose una sentencia como la que empieza por una letra mayúscula y que acaba con un signo de puntuación.
La utilización de pocos signos de puntuación como separadores da lugar a frases más largas (que también serán más difíciles de analizar por el NLP), pero reduce la casuística. Sin embargo, ampliando la cantidad de signos de puntuación utilizados da lugar a frases más cortas, pero con una casuística y complicación mayores.
El principal problema de esta técnica es el uso ambiguo de los distintos signos de puntuación. Por ejemplo, un punto puede indicar el final de una sentencia, un separador decimal en un número, una abreviatura en mitad de una sentencia o incluso una abreviatura al final de una sentencia.
El problema es desambiguar estos posibles usos.
Utilización del contexto
Podemos utilizar el carácter siguiente al signo de puntuación. Si se trata de una letra minúscula, entonces no estamos ante un final de sentencia. Si es mayúscula no se puede tomar una decisión, ya que podría tratarse de una abreviatura. En estos casos habría que analizar por ejemplo las 3 ó 4 palabras anteriores al signo de puntuación.
En general, se pueden analizar distintos contextos alrededor del signo de puntuación para determinar si se trata o no de un separador de sentencia:
  • uso de mayúsculas y minúsculas (como se ha comentado ya)
  • part of speech (por ej. Universidad de S. Antonio)
  • longitud de las palabras antes y después del punto
  • léxico de las palabras antes y después del punto
  • prefijos y sufijos
  • tipos de abreviaturas (Sr. no aparecerá al final de una frase nunca)
  • pronombres (después de un punto indican comienzo de frase)
Utilización de reglas
La utilización de reglas combinadas con listas de abreviaturas, excepciones, etc puede dar muy buenos resultados. El problema es que estas reglas suelen estar muy ligadas a un corpus y no suelen ser aplicables a otros corpus.
No obstante la utilización de estas "gramáticas" es muy efectiva habitualmente ya que puede utilizar algunos de los criterios de contexto mencionados en el apartado anterior.
Algoritmos de aprendizaje
Se han hecho algunos experimentos utilizando algoritmos de aprendizaje, sobre todo árboles de decisión, para resolver el problema de la segmentación de sentencias. Se utilizaron como variables las características contextuales de las palabras anterior y posterior al punto (longitud de la palabra, tipo de abreviatura, mayúscula/minúscula, etc).
Los resultados han sido muy satisfactorios en general, aunque ha sido necesario un corpus muy grande de entrenamiento. El problema aquí es que manualmente hay que delimitar las sentencias para que el sistema pueda aprender.

Y con esta entrada termino el tema relacionado con preprocesado del texto. Quizás un tema que no aporta mucho al NLP, pero que es imprescindible hacerlo muy cuidadosamente para que las siguientes etapas que iremos viendo puedan hacer su labor correctamente.








miércoles, 11 de enero de 2012

MyReading para Android: lectura comprensiva para primaria

Algunas personas me habían pedido que desarrollara un pequeño juego para desarrollar la lectura comprensiva, algo fundamental en la etapa de los 8 a los 10 años de nuestros hijos.
He creado esta primera versión del juego que se puede descargar gratuitamente desde el market android. De momento no tiene muchas lecturas, pero voy a ir metiendo nuevas en sucesivas versiones del juego.
Se trata de ir leyendo unos textos breves y responder después a ciertas preguntas sobre el texto. Si se supera la prueba, entonces se desbloquea una nueva lectura.
Espero que os guste y que vuestros hijos/sobrinos/nietos lo aprovechen.

Para descargarlo, hay que buscar "myreading" en el market.