Condiciones en TCL
SOLUCIONARIO
Condiciones en TCL
2024-10-30
Por
Occam's Razor

#!/usr/bin/tclsh
set n 42

puts -nonewline "Adivina en que número estoy pensando ? "
flush stdout
scan [gets stdin] "%d" v

if {$v < 0} {
    puts "Solo números positivos"
    return
}

if {$n == $v} {
    puts "Bien Hecho!";
} else {
    set h [ expr ($v > $n) ? $v - $n : $n - $v]
    puts "Sigue Probando!."
    puts "El número es [expr {$v > $n ? "MAYOR" : "MENOR"}]"
    puts  -nonewline "PISTA : "
    if     {$h < 5}  {puts "TE QUEMAS!!!"
    } elseif {$h < 10} {puts "CALENTITO!!!"
    } elseif {$h < 15} {puts "TEMPLADO"
    } else             {puts "FRIO"}
}

TCL nos proporciona un buen conjunto de instrucciones para construir nuestras condiciones. Además del operador ternario con la sintaxis clásica, nos ofrece bloques if-elseif-else con una sintaxis estilo C, utilizando {} para agrupar instrucciones.

SABIAS QUE

La posición de las llaves importa. Las llaves de apertura deben estar en la misma línea que la clausula a la que pertenecen (if, elseif o else). De la misma forma las llaves de cierre deben estar en la misma línea que las clausulas que deseemos encadenar (elseif o else). La última llave }, puede ponerse en una línea separada

TCL ofrece la instrucción switch y al igual que bash trabaja directamente sobre cadenas de caracteres (algo típico de este lenguaje). El comando switch en TCL tiene la peculiaridad de que ofrece diferentes opciones para determinar que caso debe ejecutarse:

  • -nocase. Ignora mayúsculas y minúsculas.
  • -exact. Los casos se comparan de forma exacta
  • -glob. Permite utilizar comodines para especificar los casos
  • -regexp. Permite utilizar expresiones regulares en los casos
  • -matchvar varName. Solo funciona con -regexp y nos permite indicar una variable en la que se almacenaran las partes de la expresión regular que coincidan
  • -indexvar varName. Igual a la anterior, pero almacena los índices de inicio y fin de cada ocurrencia en la variable indicada
  • --. Utilizado para indicar el final de las opciones cuando se utilizan varias

Un ejemplo normal de switch sería el siguiente:

scan [gets stdin] "%s" v

switch $v {
    "ciao" - 
    "bye" {puts "CU"  }
    "hello" {puts "Hi!!" }
    default {puts "A quien le importa?"    }
}

Podemos utilizar el caracter - para indicar que el comando asociado a un determinado caso es el mismo que el del caso siguiente…. Mirad el caso ciao en el ejemplo anterior.

TCL nos permite utilizar variables como condición para los casos, pero en este caso debemos utilizar " en lugar de {} para encerar nuestros casos, o escribir todos los casos en una línea.

set foo "hello"

switch $v "ciao" - "bye" {puts "CU"} $foo {puts "Hi!"} \
   default {puts "a quien le importa")

o

set foo "hello"
switch $v "
    \"ciao\" - 
    \"bye\" {puts \"CU\"  }
    $foo {puts \"Hi!!\" }
    default {puts \"A quien le importa?\"    } "

Nota como es necesario escapar todas las comillas dentro de los casos.

SOY NOVATO

En la mayoría de lenguajes utilizamos algún carácter para delimitar las cadenas de caracteres, normalmente las comillas dobles " o las comillas simples '. La diferencia suele ser que una permite la expansión de variables (en lenguajes que soportan esa capacidad) y las otras toman la cadena tal y como está escrita. En lenguajes como C/C++/Java, las comillas simples se utilizan para representar caracteres

Pero que sucede si queremos que nuestra cadena de caracteres contenga comillas?… Algo como "Hola "fulanito""… como podéis ver, las comillas que abrimos con la palabra fulanito serán consideradas como el final de cadena de "Hola "… Esto normalmente producirá un error. En esos casos es necesario escapar los caracteres especiales como las comillas. En prácticamente todos los lenguajes de programación, esto se consigue anteponiendo el caracter \ al caracter especial. Así, nuestra cadena se escribiría como "Hola \"fulanito\"".

Y si.. el caracter \ es necesario escaparlo también, así que veréis, sobre todo en windows cadenas como conteniendo \\ cuando definimos rutas a ficheros.

La razón es que si utilizamos las llaves la cadena no es expandida y por lo tanto la condición que creemos que estamos utilizando no es la correcta. En nuestro ejemplo usando las llaves:

set foo "hello"
switch $v {
    "ciao" - 
    "bye" {puts "CU"  }
    $foo {puts "Hi!!" }
    default {puts "A quien le importa?"    }
}

Si le damos a v el valor hello en el ejemplo de arriba, el bloque switch imprimirá A quien le importa?. Pero si le damos el valor $foo, obtendremos el resultado deseado.

Podéis comprobar esto interactivamente en la shell de tcl

% set foo "hello"
hello
% set v $foo
hello
% set v "$foo"
hello
% set v {$foo}
$foo

Como podéis ver, la variable foo es sustituida cuando se utiliza directamente o dentro de una cadena de caracteres, sin embargo, cuando la utilizamos dentro de un bloque, lo que obtenemos es el nombre literalmente lo que hemos escrito $foo en nuestro caso.

SABÍAS QUE

TCL no ofrece funciones para leer tipos especifícos de datos directamente desde un fichero. La forma de hacerlo es leer una línea completa usando [gets stdin] y luego utilizar la función scan para obtener el tipo que queramos. gets functiona igual que el gets de C y scan funciona igual que el sscanf de C.

TCL no soporta la definición de constantes, aunque hay distintas formas de conseguir ese comportamiento. La más sencilla es utilizar el convenio de nombre en mayúsculas como en otros lenguajes, pero también se puede utilizar una traza, de la siguiente forma:

set CONSTANTE 123
trace add variable CONSTANTE write {apply {args {
    global CONSTANTE
    set CONSTANT 123
    error "may not change constant"
}}}

La traza es un código que se ejecuta cuando sucede un determinado evento en el programa. En este ejemplo, cuando intentamos escribir en la variable CONSTANTE, lo que hacemos es ignorar el nuevo valor y volver a poner el valor constante que deseamos y mostrar un error… ya que el hecho de que un programa intente modificar una constante es un error lógico que debe corregirse.

Resumen

  • Soporta if ... [elsrif] ...[else] ...
  • Soporta operador terciario (cond) ? valor_Verdad : Valor_Falso
  • No soporta tipo booleano: ==0 -> FALSO y !=0 VERDADERO
  • Soporta switch
  • No soporta constantes nativamente

Interesado en aprender TCL

A través de nuestra cuenta del Programa de Afiliados de Amazon, te recomendamos este libro:

Effective Tcl/Tk Programming: Writing Better Programs with Tcl and Tk.

Como parte de este programa, recibimos una comisión por compras realizadas utilizando este enlace.


SOBRE Occam's Razor
Somos una revista libre que intenta explicar de forma sencilla conceptos tecnológicos y científicos de los que no podemos escapar. Al final, todo es más fácil de lo que parece!

 
Tu publicidad aquí :)