junio 2018

Obtener lista de impresoras compartidas en Windows usando Golang

Introducción

Trabajando en un proyecto con Go, tuve que obtener la lista de impresoras compartidas en Windows. Básicamente hacer lo mismo que ya hice aquí con PHP.

Ahora le tocó el turno a Go, y aunque al principio no fue fácil, lo conseguí.

Hace falta mencionar que utilicé un método distinto, que por el momento sólo he probado en Windows 10 pero bueno, ¿quién usa un Windows atrasado en pleno 2018? aunque creo que funciona hasta en Windows 7.

Nota: si no quieres leer todo el proceso, simplemente ve hasta abajo en donde está la función final.

Comando

Lo que tenemos que hacer es ejecutar el siguiente comando en Windows:

cmd /C wmic printer get name

Que nos da una salida como esta:

Esto es muy, muy fácil. Lo complicado es:

  1. Ejecutar el comando en Go
  2. Obtener la salida
  3. Limpiar la salida

Veamos cómo hacerlo 🙂

Código fuente en Go

Simplemente ejecutamos el comando, aquí vino la primer cosa difícil, pues hay que pasar todos los argumentos separados, no juntos.

Es decir, no hay que hacer esto:

  salida, err := exec.Command("cmd", "/C wmic printer get name").Output()

Sino esto:

  salida, err := exec.Command("cmd", "/C", "wmic", "printer", "get", "name").Output()

Esperamos la salida y la convertimos a cadena. Hora de convertirla a un array de tipo string.

El primer problema fue que Windows trata los saltos de línea como \r en lugar de \n. Al principio tuve que hacer un split con \n pero no funcionaba, entonces imprimí la cadena con fmt.Printf y el formateador %q, en donde me di cuenta de que utilizaba \r\r\n.

Así que quedó así:

salidaCadena := string(salida)
listaDeImpresoras := strings.Split(salidaCadena, "\r\r\n")

Pero incluso después de eso tenía que remover los espacios. Así que en un ciclo for recorrí el ciclo, limpié el nombre (con TrimRight para remover los espacios en blanco) y omití los vacíos o aquellos que dijeran “Name”, pues “Name” es el encabezado del comando.

var listaDeImpresorasLimpias []string
  for _, impresora := range listaDeImpresoras {
    nombreLimpio := strings.TrimRight(impresora, " ")
    if len(nombreLimpio) > 0 && nombreLimpio != "Name" {
      listaDeImpresorasLimpias = append(listaDeImpresorasLimpias, nombreLimpio)
    }
  }

Listo. Al final encerré todo en una función y se ve así:

func obtenerListaDeImpresorasCompartidasWindows() []string {
  salida, err := exec.Command("cmd", "/C", "wmic", "printer", "get", "name").Output()
  if err != nil {
    log.Fatal(err)
  }
  salidaCadena := string(salida)
  listaDeImpresoras := strings.Split(salidaCadena, "\r\r\n")
  var listaDeImpresorasLimpias []string
  for _, impresora := range listaDeImpresoras {
    nombreLimpio := strings.TrimRight(impresora, " ")
    if len(nombreLimpio) > 0 && nombreLimpio != "Name" {
      listaDeImpresorasLimpias = append(listaDeImpresorasLimpias, nombreLimpio)
    }
  }
  return listaDeImpresorasLimpias
}

Fabuloso. No olvides importar log, os/exec y strings.

Castear valores en MysQL

Introducción

MySQL es el gestor de base de datos más querido. Seguramente alguna vez vamos a querer castear un valor.

Castear un valor es cambiar su tipo, o convertirlo a otro tipo de dato. Por ejemplo, puede que necesitemos convertir una cadena a entero, a flotante, booleano, etcétera.

En mi caso tenía que cambiar todos los datos de mi tabla para que dejaran de ser flotantes y fueran enteros.

Veamos entonces algunos ejemplos de cómo castear o cambiar valores en MySQL.

Sintaxis

Bueno, MySQL en su sitio oficial dice que la sintaxis es:

CAST(columna AS NUEVO_TIPO_DE_DATO);

Es una función que castea valores. Y los tipos de datos son:

  • BINARY
  • CHAR
  • DATE
  • DATETIME
  • DECIMAL
  • JSON
  • NCHAR
  • SIGNED
  • TIME
  • UNSIGNED

Para convertir a entero elegimos SIGNED o UNSIGNED. La diferencia es que el que tiene signo soporta valores negativos, y el unsigned sólo soporta enteros (útil cuando queremos almacenar grandes números positivos).

Ejemplos

Decimal o flotante a entero

Cuando queremos convertir un valor flotante (como 9.5) a entero, el primer valor se redondeará hacia abajo o hacia arriba.

Esto depende de la parte decimal. Si la parte decimal es menor que cinco, entonces se redondea hacia abajo. Si es 5 o mayor que eso, se redondea hacia arriba.

Aquí algunas pruebas:

SELECT CAST(9.5 AS SIGNED); # Salida => 10
SELECT CAST(0.5 AS SIGNED); # Salida => 1
SELECT CAST(0.4 AS SIGNED); # Salida => 0
SELECT CAST(1.3335 AS SIGNED); # Salida => 1
SELECT CAST(1.50000 AS SIGNED); # Salida => 2

 

Entero a flotante

De esta conversión no hay mucho que decir. Simplemente redondeará y agregará los ceros a la derecha del punto.

Te invito a leer este post sobre decimales para entender mejor la conversión.

Si convertimos, por ejemplo, el entero 5 a un decimal con una precisión de 3, este se convertirá en 5.000.

Aquí algunos ejemplos:

SELECT CAST(5 AS DECIMAL(7, 3)); # Salida => 5.000
SELECT CAST(5 AS DECIMAL(7, 5)); # Salida => 5.00000

Si no entiendes el número 7, lee el post que mencioné arriba. Básicamente le decimos a MySQL que la mayor longitud del número será de 7 cifras, y el número a la derecha (3 y 5 respectivamente) es para indicar cuántos decimales se ocuparán.

En el primer caso ocupamos 3 decimales y en el segundo 5.

Entero a cadena

Igual esto es de lo más sencillo. Simplemente convertimos un entero, que será el mismo entero pero representado como cadena. 5 se convierte en “5”.

La diferencia es que podemos operar con funciones de cadena, ya que ahora sí serán de ese tipo. De todos modos he probado y no hay diferencia entre trabajar con cadena o con enteros, ya que el motor infiere.

Aunque si queremos asegurarnos, podemos hacerlo así:

SELECT CAST(123 AS CHAR); # Resultado => 123

Entero a booleano

Ahora veamos cómo convertir un número a true o false, o lo mismo que convertir un int a un booleano.

MySQL no proporciona una función para esto, pero podemos utilizar la función IF.

Conclusión

Como podemos ver, podemos castear cualquier tipo de dato a otro tipo de dato, aunque primero debemos evaluar los resultados para no confundirnos ni realizar cosas erróneas.

Generar color hexadecimal aleatorio con Javascript

Introducción

Recientemente estuve generando algunas gráficas de barras para un pequeño proyecto. Debido a que las gráficas eran llenadas de forma dinámica, necesitaba una forma de generar colores aleatorios en hexadecimal.

Recordemos que un color hexadecimal se compone de 6 caracteres que pueden ser: 0123456789ABCDEF

Por ejemplo, un color hexadecimal puede ser el #8bc34a. El color negro es #000000 y el blanco es #FFFFFF

Ahora veamos cómo generar este color en JavaScript. Por cierto, no todos serán colores agradables a la vista del usuario, pero recordemos que el objetivo es generar un color aleatorio, no un color agradable y aleatorio.

Generar color hexadecimal en JavaScript

Para ello alguien más ya escribió en esta página la función, y alguien la ha mejorado en Stackoverflow. La función queda así:

const generarColor = () => "#000000".replace(/0/g, () => (~~(Math.random() * 16)).toString(16))

Eso fue utilizando const y funciones flecha, algo de la versión ES6. Pero fácilmente se puede escribir para versiones anteriores:

var generarColor = function () {
    "#000000".replace(/0/g, function () {
      return (~~(Math.random() * 16)).toString(16);
    })
  }

Luego de eso podemos simplemente llamar a la función y listo. Aquí un ejemplo: