miércoles, 31 de julio de 2019

Usando el Traductor de Google en Excel

Desde hace ya varias versiones Microsoft ha introducido la capacidad de sus productos de Office de traducir palabras en diversos idiomas. Por supuesto que eso incluye al Excel.


:

Dicha herramienta hace uso de lo servicios de traducción de Microsoft, los cuales se incluyen como para de la suite Office (dentro de los programas), pero son de pago si se quiere acceder, por ejemplo, desde las macros (VBA) para personalizarlas de algún modo.

Una alternativa a ellos es usar Google Traductor que, si bien ha cambiado su interfase de internet y la actual dificulta un poco el acceso, no es imposible lograrlo. Por cierto, es necesario tener acceso a internet, así como tener el navegador Internet Explorer instalado (todos los Windows lo tienen, incluso el 10, así sea el Edge el predeterminado, por si acaso).

Entonces, ahora quiero comentar que he usado el objeto Internet Explorer dado que es más fácil su uso, aunque acepto que para hacer Web Scraping (o similares) es más rápido usar MSXML2 (lo usaré en una próxima oportunidad).

Ahora sí, manos a la obra. Lo primero es comentarles que inicialmente pensé en detectar los elementos/objetos de la web del traductor (Enlace) y enviar el texto a traducir para que ellos ocurra de modo automático en los idiomas predeterminados ¿cuál era el dilema con eso? Pues elegir algún otro idioma, a través de las listas respectivas en dicha web, suponía una dificultad cuya programación, además de costar buen tiempo, no necesariamente iba a ser de fácil entendimiento. Decidido eso opte por usar otro método que se me ocurrió al observar el enlace que se genera cuando uno ingresa algún texto que desea traducir ¿cómo es eso? Pongamos por ejemplo la palabra “Hola”.

¿Notan lo qué ocurre? Veámoslo con más detenimiento:

https://translate.google.com/#view=home&op=translate&sl=es&tl=en&text=Hola

Si aún no lo notan, cambien la palabra por “Adiós” y obtendrán esto:

https://translate.google.com/#view=home&op=translate&sl=es&tl=en&text=Adios

“sl” por “star Lenguage” y “lt” por “translated language” y después del “Text=” el texto a traducir. En el caso de los idiomas, no fue difícil darse cuenta que respondía al código de idiomas según ISO 639-1 (Enlace). Hallado eso, se me ocurrió que, mandando desde el Excel el enlace con la combinación de idiomas necesario más el texto requerido, pues daría como resultado dicho texto traducido y aquel podría extraerse de la web. Igual antes hice unas pruebas con signos diversos a ver si significaban algún dilema. Para que se entienda, ingresen esto “Hola ¿cómo estás? Yo bien, espero tú igual” (sin las comillas) y el enlace será el siguiente:

https://translate.google.com/#view=home&op=translate&sl=es&tl=en&text=Hola%20¿cómo%20estás%3F%20Yo%20bien%2C%20espero%20tú%20igual

Como se aprecia, los espacios en blanco y algunos caracteres son reemplazados por su correspondiente código hexadecimal precedido de un signo “%”. Después de algunas pruebas, pude ver cuáles eran y los coloqué en una hoja que llamé “Signos”, del siguiente modo:

He omitido ahí el signo de porcentaje (%) y el de interrogación de cierre (¿), ya explicaré el por qué. Del mismo modo elegí algunos de los idiomas y los coloqué así en la misma hoja:

En una hoja que he llamado “Traductor” vamos a usar la celda A2 para ingresar el texto a traducir; si bien Google Traductor permite hasta 5000 caracteres, por una cuestión de orden vamos a poner un límite de 4000 en nuestro libro. En C2 y D2 incluiremos listas desplegables de validación basadas en la columna F de la hoja “Signos”, la única diferencia es que en C” incluiremos “Automático” y en D2 no, de ese modo de necesitar traducir un texto cuyo idioma se desconoce, basta usar dicha opción para que Google Traductor lo detecte.

Si bien el texto a cambiar lo vamos a colocar en A2, para luego cambiar, lo correspondiente, a código hexadecimal, enviaremos todo a F1.

Dim MiHoja As Worksheet 
Set MiHoja = Worksheets("Traductor") 
MiHoja.Range("F1").Value = MiHoja.Range("A2").Value 

Luego convertiremos los caracteres necesarios de F1 en código hexadecimal. Vamos a comenzar por los signos de porcentaje (%) primero usando Replace, ya que el código hexadecimal debe ir precedido de dicho signo en cada caso y entonces es mejor cambiarlo(s) primero pues si se hace a la par de lo demás (con un bucle, como usaremos), podría reemplazarse todo lo que sí necesitaremos para enviar en el enlace que del traductor.

With MiHoja.Range("F1")
     .Replace What:="%", Replacement:="%25", LookAt:=xlPart, _
         SearchOrder:=xlByRows 

25 es el hexadecimal del signo %, y obviamente también debe ir precedido de ese mismo signo (%).

Luego, igualmente usando Replace, con un bucle (For Each) recorreremos todos los códigos de los caracteres que deseamos reemplazar en la celda F1 y los convertiremos en hexadecimales precedidos de %.

For Each Celda In Worksheets("Signos").Range("C2:C20")
         .Replace What:=ChrW(Celda.Value), Replacement:="%" & Celda.Offset(0, -2).Value, LookAt:=xlPart, _
             SearchOrder:=xlByRows
Next Celda 

Por último, haremos los mismo con el signo ?. Lo dejamos al último dado que puede ser confundido por Excel y/o VBA como un comodín y hacer que cambie todo el texto por él.

   .Replace What:="~?", Replacement:="%3F", LookAt:=xlPart, _
         SearchOrder:=xlByRows
 End With 

Para los idiomas haremos algo parecido, pero usando Find para encontrar el(los) elegidos y su diminutivo dado que eso último es lo que enviaremos al enlace de la web. Para ello usaremos dos variables.

'El uso de Let no es necesario, se puede dar el valor sin usarlo (es equivalente), pero 
'tengo la costumbre de dejarlo. Igual, en casos como este se puede omitir Value, pero 
'considero que colocarlo permite entender mejor a que propiedad se hace referencia 
Dim CeldaaEncontrar As Range 
Dim ValoraBuscar$, PrimerIdioma$, SegundoIdioma$ 
Let ValoraBuscar = MiHoja.Range("C2").Value 
Set CeldaaEncontrar = Worksheets("Signos").Range("F2:F62").Find(ValoraBuscar) 
Let PrimerIdioma = CeldaaEncontrar.Offset(0, 1).Value 
Let ValoraBuscar = MiHoja.Range("D2").Value 
Set CeldaaEncontrar = Worksheets("Signos").Range("F3:F62").Find(ValoraBuscar) 
Let SegundoIdioma = CeldaaEncontrar.Offset(0, 1).Value 

Hasta aquí ya tenemos el texto con los caracteres convertidos en hexadecimal (en F1) y en variables los diminutivos de los idiomas, aquí lo que hay que hacer es usar el objeto Internet Explorer, que abra la web del traductor con toda la cadena necesaria y con eso lograremos que lo traduzca.

Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")
With IE
     .Navigate "https://translate.google.com/#view=home&op=translate&sl=" & PrimerIdioma & "&tl=" & SegundoIdioma & "&text=" & MiHoja.Range("F1").Value
      
      Do Until .ReadyState = 4
         DoEvents
     Loop     
End With 
Como ven, he incluido un bucle que de tiempo para que cargue de forma correcta y de ese modo tener la traducción. Para finalizar solo queda extraer dicha traducción y enviarla a nuestra celda A5, borrar F1, proteger la hoja y cerrar el Internet Explorer (si bien nunca se verá el navegador, sí se abre).
With MiHoja
     .Range("A5").Value = IE.document.querySelector(".tlid-translation.translation").innerText
     .Range("F1").ClearContents
     .Protect "1234"
End With 
IE.Quit 

Y listo, ya tenemos nuestro traductor de Google en nuestro archivo de Excel. La macro completa quedará así:

Sub Traductor ()
Dim Celda As Range, CeldaaEncontrar As Range
Dim IE As Object 
Dim MiHoja As Worksheet 
Dim ValoraBuscar$, PrimerIdioma$, SegundoIdioma$ 

Set MiHoja = Worksheets("Traductor") 

If MiHoja.Range("A2") = "" Or MiHoja.Range("C2") = "" Or MiHoja.Range("D2") = "" Then
     MsgBox "No debe dejar vacío los campos del texto a traducir o los idiomas", vbOKOnly, "Todos Sobre Excel"
     Exit Sub
End If

If Len(MiHoja.Range("A2")) >= 4000 Then
     MsgBox "No debes exceder de 4000 caracteres, por favor cambiar. Tienes " & Len(MiHoja.Range("A2")) & " caracteres en este momento", vbOKOnly, "Todos Sobre Excel"
     Exit Sub
End If

Application.ScreenUpdating = False
MiHoja.Unprotect "1234" 
MiHoja.Range("F1").Value = MiHoja.Range("A2").Value

With MiHoja.Range("F1")
'Convertimos los signos % a hexadecimal, lo hacemos antes de los demás ya que % es un signo usado 
'varias veces y entraríamos casi en un bucle de convertirlo junto con todos los otros signos
     .Replace What:="%", Replacement:="%25", LookAt:=xlPart, _
         SearchOrder:=xlByRows 
'en este bucle convertimos los signos a hexadecimal
     For Each Celda In Worksheets("Signos").Range("C2:C20")
         .Replace What:=ChrW(Celda.Value), Replacement:="%" & Celda.Offset(0, -2).Value, LookAt:=xlPart, _
             SearchOrder:=xlByRows
     Next Celda 
'aquí lo hacemos con el signo ?, ya que si se usa el Replace junto con los demás signos y este, en un bucle, transforma todo
     .Replace What:="~?", Replacement:="%3F", LookAt:=xlPart, _
         SearchOrder:=xlByRows
End With

'El uso de Let no es necesario, se puede dar el valor sin usarlo (es equivalente), pero 
'tengo la costumbre de dejarlo. Igual, en casos como este se puede omitir Value, pero 
'considero que colocarlo permite entender mejor a que propiedad se hace referencia 
Let ValoraBuscar = MiHoja.Range("C2").Value 
Set CeldaaEncontrar = Worksheets("Signos").Range("F2:F62").Find(ValoraBuscar) 
Let PrimerIdioma = CeldaaEncontrar.Offset(0, 1).Value 
Let ValoraBuscar = MiHoja.Range("D2").Value 
Set CeldaaEncontrar = Worksheets("Signos").Range("F3:F62").Find(ValoraBuscar) 
Let SegundoIdioma = CeldaaEncontrar.Offset(0, 1).Value 
Set IE = CreateObject("InternetExplorer.Application")

With IE
     .Navigate "https://translate.google.com/#view=home&op=translate&sl=" & PrimerIdioma & "&tl=" & SegundoIdioma & "&text=" & MiHoja.Range("F1").Value
      Do Until .ReadyState = 4
         DoEvents
     Loop      
End With

With MiHoja
     .Range("A5").Value = IE.document.querySelector(".tlid-translation.translation").innerText
     .Range("F1").ClearContents
     .Protect "1234"
 End With 

IE.Quit

'En módulos estándar no es necesario colocar en True el ScreenUpdating ya que con el 
'End Sub lo hace, pero es mi costumbre de programador colocarlo 
Application.ScreenUpdating = True 
'Asimismo, el End Sub libera las variables, pero siempre uso el Nothing por costumbre
Set CeldaaEncontrar = Nothing: Set MiHoja = Nothing: Set IE = Nothing 
MsgBox "Traducción realizada", vbOKOnly, "Todos Sobre Excel" 

End Sub 


Espero les guste, hasta la próxima.

Abraham Valencia

Descargue el ejemplo aquí

sábado, 20 de julio de 2019

Gráficos con listas de validación (desplegables)

En muchas ocasiones he visto en los foros y comunidades que muchas personas preguntan sobre la posibilidad de mostrar diversos datos relacionados en un mismo gráfico, pero en tiempos distintos. Para que se entienda mejor, vamos a suponer que tengo cuatro tiendas y sus ventas acumuladas por siete años.
:

Podríamos tener todos esos datos en un solo gráfico (columnas apiladas, líneas apiladas, etc.), pero, como ya comenté, no es raro que se quiera ver tienda por tienda en ese mismo gráfico sin necesidad de crear otros. Mi primera respuesta es usar un Gráfico Dinámico, aunque he notado que a algunas personas se les dificulta su uso y por eso la alternativa que plantearé hoy.

Para comenzar, y pensando que usaremos los datos mostrados líneas arriba, vamos a suponer que en el mismo gráfico queremos los resultaos de las ventas de cada año, pero verlos de tienda en tienda, entonces copiaremos los encabezados de las filas de este modo:


Luego en la celda A11 agregaremos una lista de validación con los nombres de todas las tiendas (estoy asumiendo que eso sí saben cómo hacerlo).

Luego coloca esta fórmula en la celda B12:

=INDICE($B$2:$E$8;COINCIDIR(A12;$A$2:$A$8;0);COINCIDIR($A$11;$B$1:$E$1;0))
Por si no se entiende la fórmula, sugiero ver este artículo: Enlace. Luego copia o arrastra la fórmula hasta B18. Si hemos hecho todo bien y elegimos una tienda en la lista de la celda A11, tendremos algo así como resultados:

Ahora lo que haremos es situar el cursor sobre cualquiera de las celdas del segundo grupo de datos e insertaremos un gráfico. Sugiero usar el de “columnas agrupadas”.

El gráfico inicial seguro se verá algo así:

Si cambiamos el formato podemos dejar, finalmente, el gráfico a nuestro gusto.

Hecho eso, conforme cambiamos la lista desplegable, los datos del gráfico van variando.



Espero les sea útil. Hasta la próxima.

Abraham Valencia

Descargue el ejemplo aquí

domingo, 7 de julio de 2019

Completar y buscar datos usando INDICE y COINCIDIR

Probablemente, en Excel, la función más usada para buscar y/o completar datos sea BUSCARV. Dicha función nos permite lo mencionado, pero con la limitación de que la referencia siempre debe de estar a la izquierda de nuestros datos. ¿Cómo podemos hacer si tenemos dos referencias y ellas incluso están no solo a la izquierda sino, por ejemplo, en una fila superior? Si bien podríamos pensar en anidar BUSCARV con otras funciones, en esta ocasión vamos a aprender a hacerlo usando INDICE y COINCIDIR.

Comencemos con INDICE. Microsoft nos dice que dicha función devuelve un valor o la referencia a un valor desde una tabla o rango. Hay dos formas de utilizar la función; la primera es si se desea devolver el valor de una celda especificada o de una matriz de celdas (Forma de matriz), y la segunda es si se desea devolver una referencia a las celdas especificadas (Forma de referencia). Para este caso la forma que nos interesa es la de matriz.

Microsoft nos dice lo siguiente sobre la forma de matriz de INDICE: Devuelve el valor de un elemento de una tabla o matriz, seleccionado por los índices de número de fila y de columna. Asimismo, la función tiene los siguientes argumentos:

INDICE(matriz; Núm_fila; [Núm_columna])

Argumento

Descripción

Matriz

Obligatorio. Es un rango de celdas o una constante de matriz.

Núm_fila

Obligatorio. Selecciona la fila de la matriz desde la cual devolverá un valor. Si se omite Núm_fila, se requiere Núm_columna.

Núm_columna

Opcional. Selecciona la columna de la matriz desde la cual devolverá un valor. Si se omite Núm_columna, se necesita Núm_fila.

Es decir, si en la función señalamos un rango de celdas o una matriz, e indicamos la fila y/o columna, nos devolverá el valor que coindice con esa fila/columna dentro del rango o matriz indicado. Para que se entienda mejor usaremos un par de ejemplos. Trabajaremos con datos que están en la hoja de la siguiente forma:

Entonces, si en cualquier celda colocamos esta fórmula:

=INDICE(B2:E8;2;2)

El resultado en la celda será de 400 ¿por qué? Porque en el rango de celdas que hemos usado (B2:E8) el valor correspondiente a la intersección de la segunda fila y segunda columna es 400 ¿se entendió? Vamos con un ejemplo más para que quede claro. Usemos ahora esta fórmula:

=INDICE(B2:E8;6;4)

El resultado es 80. Intersección de la sexta fila y la cuarta columna del rango de datos.

Ahora vamos con COINCIDIR. Microsoft nos dice que la función COINCIDIR busca un elemento determinado en un intervalo de celdas y después devuelve la posición relativa de dicho elemento en el rango. Por ejemplo, si el rango A1:A3 contiene los valores 5, 25 y 38, la fórmula =COINCIDIR(25,A1:A3,0) devuelve el número 2, porque 25 es el segundo elemento del rango. Para entender mejor dicha función, esta tiene los siguientes argumentos:

COINCIDIR(Valor_buscado, Matriz_buscada, [Tipo_de_coincidencia])

Argumento

Descripción

Valor_buscado

Obligatorio. Es el valor que desea buscar en Matriz_buscada.

Matriz_buscada

Obligatorio. Es el rango de celdas en que se realiza la búsqueda.

Tipo_de_coincidencia

Opcional. Puede ser el número -1, 0 o 1. El argumento Tipo_de_coincidencia específica cómo Excel hace coincidir el Valor_buscado con los valores de Matriz_buscada. El valor predeterminado de este argumento es 1 (1 = Menor que, 0 = Coincidencia exacta, -1 = Mayor que)

Si con los datos del ejemplo usamos la siguiente fórmula:

=COINCIDIR("Abraham";A2:A8;0)

El resultado que tendremos será 3, ya que mi nombre es está en la tercera posición del rango ingresado. Un ejemplo más:

=COINCIDIR(2016;B1:E1;0)

El resultado que tendremos será 2, ya que el 2016 ocupa la segunda posición en el rango ingresado.

Entonces ¿cómo aplicamos todo esto para buscar y/o completar datos? Veamos algunos ejemplos en donde anidemos dichas funciones en fórmulas que nos permitan cumplir dicha tarea.

Seguiremos trabajando con el mismo grupo de datos, pero ahora supongamos que queremos saber cuánto ganó Pedro el año 2017. Entonces usaremos una fórmula así:

=INDICE(B2:E8; COINCIDIR("Pedro";A2:A8;0);COINCIDIR(2017;B1:E1;0))

El resultado será 200 ¿por qué? Dentro de la función INDICE hemos reemplazado los argumentos Núm_fila y Núm_columna por COINCIDIR, ya que COINCIDIR nos trae el número de la posición del nombre “Pedro” dentro de un rango y el otro COINCIDIR usado hace lo mismo con el “2017” buscado. La fórmula por lo tanto se interpreta así:

=INDICE(B2:E8; 4; 3)

Un último ejemplo. Supongamos que tenemos dos listas de validación, una en la celda H2 basada en el rango de años y otra en la celda H3 basada en el rango de nombres y en la celda H3 la siguiente fórmula:

=INDICE(B2:E8;COINCIDIR(H3;A2:A8;0);COINCIDIR(H2;B1:E1;0))

De ese modo al elegir los dos valores en la lista correspondiente, en H3 tendremos siempre el resultado del monto en que coincidan dichos valores dentro de la matriz.

Espero les sea útil. Hasta la próxima.

Abraham Valencia

Descargue el ejemplo de aquí