¿Cómo escribir un script de shell para asignar calificaciones de letras a rangos numéricos?

19

Quiero hacer un guión que le solicite un número entre 0-100 y luego le otorgue la calificación basada en el número.

Me gustaría en bash.

PS3='Please enter your choice: '
(Something here)

do
case $
    "0-59")
        echo "F"
        ;;
    "60-69")
        echo "D"
        ;;
    "70-79")
        echo "C"
        ;;
    "Quit")
        break
        ;;
    *) echo invalid option;;
esac
done
Paté del templo
fuente

Respuestas:

20

Brevedad vs. Legibilidad: un término medio

Como ha visto, este problema admite soluciones que son moderadamente largas y algo repetitivas pero altamente legibles ( respuestas bash de terdon y AB ), así como aquellas que son muy cortas pero no intuitivas y mucho menos auto-documentadas (la pitón de Tim y bash respuestas y la respuesta perl de glenn jackman ). Todos estos enfoques son valiosos.

También puede resolver este problema con código en el medio del continuo entre compacidad y legibilidad. Este enfoque es casi tan legible como las soluciones más largas, con una longitud más cercana a las soluciones pequeñas y esotéricas.

#!/usr/bin/env bash

read -erp 'Enter numeric grade (q to quit): '
case $REPLY in [qQ]) exit;; esac

declare -A cutoffs
cutoffs[F]=59 cutoffs[D]=69 cutoffs[C]=79 cutoffs[B]=89 cutoffs[A]=100

for letter in F D C B A; do
    ((REPLY <= cutoffs[$letter])) && { echo $letter; exit; }
done
echo "Grade out of range."

En esta solución bash, he incluido algunas líneas en blanco para mejorar la legibilidad, pero puede eliminarlas si lo desea aún más corto.

Se incluyen líneas en blanco, esto en realidad es solo un poco más corto que una variante compacta, aún bastante legible, de la solución bash de AB . Sus principales ventajas sobre ese método son:

  • Es mas intuitivo.
  • Es más fácil cambiar los límites entre las calificaciones (o agregar calificaciones adicionales).
  • Acepta automáticamente la entrada con espacios iniciales y finales (consulte a continuación para obtener una explicación de cómo (( ))funciona).

Las tres ventajas surgen porque este método utiliza la entrada del usuario como datos numéricos en lugar de examinar manualmente sus dígitos constituyentes.

Cómo funciona

  1. Leer la entrada del usuario. Permítales usar las teclas de flecha para moverse en el texto que ingresaron ( -e) y no interpretarlo \como un carácter de escape ( -r).
    Esta secuencia de comandos no es una solución rica en funciones, consulte a continuación para un refinamiento, pero esas funciones útiles solo hacen que sean dos caracteres más largos. Recomiendo usar siempre -rcon read, a menos que sepa que necesita dejar que el usuario proporcione \escapes.
  2. Si el usuario escribió qo Q, salga.
  3. Crear una matriz asociativa ( ). Rellene con la calificación numérica más alta asociada con cada calificación de letra.declare -A
  4. Recorra las calificaciones de letras de menor a mayor, verificando si el número proporcionado por el usuario es lo suficientemente bajo como para caer en el rango numérico de cada calificación de letra.
    Con la (( ))evaluación aritmética, no es necesario expandir los nombres de las variables $. (En la mayoría de las otras situaciones, si desea utilizar el valor de una variable en lugar de su nombre, debe hacerlo ).
  5. Si cae en el rango, imprima el grado y salga .
    Por brevedad, uso el cortocircuito y el operador ( &&) en lugar de un if- then.
  6. Si el ciclo finaliza y no se ha igualado ningún rango, suponga que el número ingresado es demasiado alto (más de 100) y dígale al usuario que está fuera de rango.

Cómo se comporta esto, con información extraña

Al igual que las otras soluciones cortas publicadas, ese script no verifica la entrada antes de asumir que es un número. La evaluación aritmética ( (( ))) elimina automáticamente los espacios en blanco iniciales y finales, por lo que no hay problema, pero:

  • La entrada que no parece un número en absoluto se interpreta como 0.
  • Con una entrada que parece un número (es decir, si comienza con un dígito) pero contiene caracteres no válidos, el script emite errores.
  • De entrada de múltiples dígitos empezando con 0se interpreta como siendo en octal . Por ejemplo, el script le dirá que 77 es una C, mientras que 077 es una D. Aunque algunos usuarios pueden querer esto, probablemente no lo hagan y puede causar confusión.
  • En el lado positivo, cuando se le da una expresión aritmética, este script lo simplifica automáticamente y determina el grado de letra asociado. Por ejemplo, le dirá que 320/4 es una B.

Una versión ampliada y totalmente destacada

Por esas razones, es posible que desee usar algo como este script expandido, que verifica para asegurarse de que la entrada sea buena e incluye algunas otras mejoras.

#!/usr/bin/env bash
shopt -s extglob

declare -A cutoffs
cutoffs[F]=59 cutoffs[D]=69 cutoffs[C]=79 cutoffs[B]=89 cutoffs[A]=100

while read -erp 'Enter numeric grade (q to quit): '; do
    case $REPLY in  # allow leading/trailing spaces, but not octal (e.g. "03") 
        *( )@([1-9]*([0-9])|+(0))*( )) ;;
        *( )[qQ]?([uU][iI][tT])*( )) exit;;
        *) echo "I don't understand that number."; continue;;
    esac

    for letter in F D C B A; do
        ((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }
    done
    echo "Grade out of range."
done

Esta sigue siendo una solución bastante compacta.

¿Qué características agrega esto?

Los puntos clave de este script expandido son:

  • Validación de entrada. El script de terdon verifica la entrada con , así que muestro otra forma, que sacrifica algo de brevedad pero es más robusta, lo que permite al usuario ingresar espacios iniciales y finales y se niega a permitir una expresión que podría o no ser octal (a menos que sea cero) .if [[ ! $response =~ ^[0-9]*$ ]] ...
  • Lo he usado casecon globbing extendido en lugar de [[con el operador de =~ coincidencia de expresiones regulares (como en la respuesta de terdon ). Lo hice para mostrar que (y cómo) también se puede hacer de esa manera. Globs y regexps son dos formas de especificar patrones que coinciden con el texto, y cualquiera de los métodos está bien para esta aplicación.
  • Al igual que el script bash de AB , he incluido todo en un bucle externo (excepto la creación inicial de la cutoffsmatriz). Solicita números y otorga las letras correspondientes siempre que la entrada del terminal esté disponible y el usuario no le haya dicho que abandone. A juzgar por el do... donealrededor del código en tu pregunta, parece que quieres eso.
  • Para que dejar de fumar sea fácil, acepto cualquier variante que distinga entre mayúsculas y minúsculas de qo quit.

Este script utiliza algunas construcciones que pueden ser desconocidas para los principiantes; se detallan a continuación.

Explicación: uso de continue

Cuando quiero omitir el resto del cuerpo del whilebucle externo , utilizo el continuecomando. Esto lo lleva de vuelta a la parte superior del bucle, para leer más entradas y ejecutar otra iteración.

La primera vez que hago esto, el único bucle en el que estoy es el whilebucle externo , por lo que puedo llamar continuesin argumento. (Estoy en una caseconstrucción, pero eso no afecta la operación de breako continue.)

        *) echo "I don't understand that number."; continue;;

La segunda vez, sin embargo, estoy en un forbucle interno que está anidado dentro del whilebucle externo . Si lo usara continuesin argumento, esto sería equivalente continue 1y continuaría con el forbucle interno en lugar del whilebucle externo .

        ((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }

Entonces, en ese caso, uso continue 2para hacer que bash encuentre y continúe el segundo bucle.

Explicación: caseetiquetas con globos

Yo no uso casede averiguar qué grado de la letra bin varios cae en (como en la respuesta de fiesta AB ). Pero sí uso casepara decidir si la entrada del usuario debe considerarse:

  • un número válido *( )@([1-9]*([0-9])|+(0))*( )
  • el comando para dejar de fumar, *( )[qQ]?([uU][iI][tT])*( )
  • cualquier otra cosa (y por lo tanto entrada no válida), *

Estos son globos de concha .

  • A cada uno le sigue una )apertura que no coincide con ninguna apertura (, que es casela sintaxis para separar un patrón de los comandos que se ejecutan cuando coincide.
  • ;;es casela sintaxis para indicar el final de los comandos que se ejecutarán para una coincidencia de caso particular (y que no se deben probar los casos posteriores después de ejecutarlos).

El globbing de shell ordinario proporciona *coincidir con cero o más caracteres, ?para coincidir exactamente con un carácter y clases / rangos de caracteres [ ]entre paréntesis. Pero estoy usando globbing extendido , que va más allá de eso. El globbing extendido está habilitado de manera predeterminada cuando se usa de forma bashinteractiva, pero está deshabilitado de manera predeterminada cuando se ejecuta un script. El shopt -s extglobcomando en la parte superior del script lo activa.

Explicación: Globbing extendido

*( )@([1-9]*([0-9])|+(0))*( ), que comprueba la entrada numérica , coincide con una secuencia de:

  • Cero o más espacios ( *( )). La *( )construcción coincide con cero o más del patrón entre paréntesis, que aquí es solo un espacio.
    En realidad, hay dos tipos de espacios en blanco horizontales, espacios y pestañas, y a menudo también es deseable hacer coincidir las pestañas. Pero no me preocupo por eso aquí, porque este script está escrito para entrada manual, interactiva y el -eindicador para readhabilitar la línea de lectura de GNU. Esto es para que el usuario pueda moverse hacia adelante y hacia atrás en su texto con las teclas de flecha izquierda y derecha, pero tiene el efecto secundario de evitar generalmente que las pestañas se ingresen literalmente.
  • Una aparición ( @( )) de cualquiera de ( |):
    • Un dígito distinto de cero ( [1-9]) seguido de cero o más ( *( )) de cualquier dígito ( [0-9]).
    • Uno o más ( +( )) de 0.
  • Cero o más espacios ( *( )), nuevamente.

*( )[qQ]?([uU][iI][tT])*( ), que comprueba el comando salir , coincide con una secuencia de:

  • Cero o más espacios ( *( )).
  • qo Q( [qQ]).
  • Opcionalmente, es decir, cero o una ocurrencia ( ?( )) - de:
    • uo U( [uU]) seguido de io I( [iI]) seguido de to T( [tT]).
  • Cero o más espacios ( *( )), nuevamente.

Variante: Validación de entrada con una expresión regular extendida

Si prefiere probar la entrada del usuario contra una expresión regular en lugar de un glob de shell, es posible que prefiera usar esta versión, que funciona igual pero usa [[y =~(como en la respuesta de terdon ) en lugar de caseglobbing extendido.

#!/usr/bin/env bash
shopt -s nocasematch

declare -A cutoffs
cutoffs[F]=59 cutoffs[D]=69 cutoffs[C]=79 cutoffs[B]=89 cutoffs[A]=100

while read -erp 'Enter numeric grade (q to quit): '; do
    # allow leading/trailing spaces, but not octal (e.g., "03")
    if [[ ! $REPLY =~ ^\ *([1-9][0-9]*|0+)\ *$ ]]; then
        [[ $REPLY =~ ^\ *q(uit)?\ *$ ]] && exit
        echo "I don't understand that number."; continue
    fi

    for letter in F D C B A; do
        ((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }
    done
    echo "Grade out of range."
done

Las posibles ventajas de este enfoque son que:

  • En este caso particular, la sintaxis es un poco más simple, al menos en el segundo patrón, donde verifico el comando salir. Esto se debe a que pude establecer la nocasematchopción de shell, y luego todas las variantes de casos qy quitfueron cubiertas automáticamente.

    Eso es lo que hace el shopt -s nocasematchcomando. El shopt -s extglobcomando se omite ya que no se usa globbing en esta versión.

  • Las habilidades de expresión regular son más comunes que el dominio de los globos externos de bash.

Explicación: expresiones regulares

En cuanto a los patrones especificados a la derecha del =~operador, así es como funcionan esas expresiones regulares.

^\ *([1-9][0-9]*|0+)\ *$, que comprueba la entrada numérica , coincide con una secuencia de:

  • El comienzo, es decir, el borde izquierdo, de la línea ( ^).
  • Cero o más ( *postfix aplicado) espacios. Normalmente, un espacio no necesita ser \-escapado en una expresión regular, pero esto es necesario [[para evitar un error de sintaxis.
  • Una subcadena ( ( )) que es una u otra ( |) de:
    • [1-9][0-9]*: un dígito distinto de cero ( [1-9]) seguido de cero o más ( *, postfix aplicado) de cualquier dígito ( [0-9]).
    • 0+: uno o más ( +, postfix aplicado) de 0.
  • Cero o más espacios ( \ *), como antes.
  • El final, es decir, el borde derecho, de la línea ( $).

A diferencia de las caseetiquetas, que coinciden con la expresión completa que se está probando, =~devuelve verdadero si alguna parte de su expresión de la izquierda coincide con el patrón dado como su expresión de la derecha. Es por eso que los anclajes ^y $, que especifican el principio y el final de la línea, son necesarios aquí, y no se corresponden sintácticamente con nada que aparezca en el método con casey extglobs.

Los paréntesis son necesarios para hacer ^y $unirse a la disyunción de [1-9][0-9]*y 0+. De lo contrario, sería la disyunción de ^[1-9][0-9]*y 0+$, y coincidiría con cualquier entrada que comience con un dígito distinto de cero o que termine con un 0(o ambos, que aún podrían incluir no dígitos entre ellos).

^\ *q(uit)?\ *$, que comprueba el comando salir , coincide con una secuencia de:

  • El comienzo de la línea ( ^).
  • Cero o más espacios ( \ *ver explicación anterior).
  • La carta q. O Q, ya que shopt nocasematchestá habilitado.
  • Opcionalmente, es decir, cero o una aparición (postfix ?) de la subcadena ( ( )):
    • u, seguido de i, seguido de t. O, ya que shopt nocasematchestá habilitado upuede ser U; independientemente, ipuede ser I; e independientemente, tpuede ser T. (Es decir, las posibilidades no se limitan a uity UIT.)
  • Cero o más espacios de nuevo ( \ *).
  • El final de la línea ( $).
Eliah Kagan
fuente
3
dime la verdad ... cuanto tiempo ha tomado? ;)
heemayl
44
@heemayl No estoy totalmente seguro, ya que lo escribí en muchas partes pequeñas durante todo el día (seguido de una lectura completa y ediciones, justo antes de publicar). Sin embargo, estoy bastante seguro de que terminó tardando más de lo que hubiera pensado cuando comencé, si hubiera estado pensando en cuánto tiempo me tomaría. :)
Eliah Kagan
66
escribe más y más, necesito un libro de tus respuestas.
Grijesh Chauhan
TL; DR pero me hizo reír de todos modos!
Fabby
todo, desde el título hasta la explicación, es bueno. Lo entendí al principio, pero lo leí de nuevo solo porque quería
Sumeet Deshmukh
23

Ya tienes la idea básica. Si desea codificar esto bash(que es una opción razonable ya que es el shell predeterminado en Ubuntu y la mayoría de los otros Linux), no puede usarlo caseporque no comprende los rangos. En su lugar, podría usar if/ else:

#!/usr/bin/env bash

read -p "Please enter your choice: " response

## If the response given did not consist entirely of digits
if [[ ! $response =~ ^[0-9]*$ ]]
then
    ## If it was Quit or quit, exit
    [[ $response =~ [Qq]uit ]] && exit
    ## If it wasn't quit or Quit but wasn't a number either,
    ## print an error message and quit.
    echo "Please enter a number between 0 and 100 or \"quit\" to exit" && exit
fi
## Process the other choices
if [ $response -le 59 ]
then
    echo "F"
elif [ $response -le 69 ]
then
    echo "D"
elif  [ $response -le 79 ]
then
    echo "C"
elif  [ $response -le 89 ]
then
    echo "B"
elif [ $response -le 100 ]
then
    echo "A"
elif [ $response -gt 100 ]
then
    echo "Please enter a number between 0 and 100"
     exit
fi
terdon
fuente
44
Se -gepuede eliminar un montón de esas pruebas, presumiblemente, ya que las está usando elif. ¿Y sin amor (( $response < X ))?
Muru
2
@muru cierto, gracias. Estaba atrapado pensando en rangos de números, pero no había razón para hacerlo. En cuanto a (( $response < X )), claro, pero me parece más claro y el OP es obviamente nuevo en bash scripting.
terdon
12
#!/bin/bash

while true
do
  read -p "Please enter your choice: " choice

  case "$choice"
   in
      [0-9]|[1-5][0-9])
          echo "F"
          ;;
      6[0-9])
          echo "D"
          ;;
      7[0-9])
          echo "C"
          ;;
      8[0-9])
          echo "B"
          ;;
      9[0-9]|100)
          echo "A"
          ;;
      [Qq])
          exit 0
          ;;
      *) echo "Only numbers between 0..100, q for quit"
          ;;
  esac
done

y una versión más compacta (Thx @EliahKagan ):

#!/usr/bin/env bash

while read -erp 'Enter numeric grade (q to quit): '; do
    case $REPLY in
        [0-9]|[1-5][0-9])   echo F ;;
        6[0-9])             echo D ;;
        7[0-9])             echo C ;;
        8[0-9])             echo B ;;
        9[0-9]|100)         echo A ;;

        [Qq])               exit ;;
        *)                  echo 'Only numbers between 0..100, q for quit' ;;
    esac
done
AB
fuente
1
Esos son los rangos de caracteres, ¿verdad? es [0-59]decir, cualquier carácter de 0,1,2,3,4,5 o 9 y así sucesivamente. No veo cómo eso puede funcionar para valores numéricos .
steeldriver
3
No tienes que ser FGITW todo el tiempo. Tómese su tiempo, escriba buenas respuestas. Mira cómo funcionan terdon o Eliah Kagan.
Muru
@AB He notado que esta solución se puede acortar, principalmente a través de cambios estilísticos, sin dejar de ser bastante legible. La brevedad es raramente la consideración más importante, así que no creo que deba cambiar lo que tiene de esta manera. Pero dado que la forma más compacta no ocupa mucho espacio, puede considerar mostrarla también, en caso de que algunos lectores quieran un guión más corto que funcione de la misma manera. (Si lo desea, siéntase libre de usar mi versión abreviada, o cualquier variación en ella).
Eliah Kagan
9

Todas las instalaciones de Ubuntu tienen Python, así que aquí hay una secuencia de comandos de Python . Si necesita que esté en bash, también he escrito el equivalente como un script de shell .

print (chr(75-max(5,int('0'+raw_input('Enter the number: ')[:-1]))))

Para ejecutarlo, guárdelo en un archivo (por ejemplo grade.py) y luego ejecútelo en la terminal con esto:

python grade.py

Esto es lo que verás:

Enter the number: 65
E

¿Como funciona esto?

  1. Tomar entrada - 65.
  2. Agregue un 0 al principio - 065.
  3. Eliminar el último carácter - 06.
  4. 75 restan ese número - 70.
  5. Convierte a una letra (A es 65, B es 66) - E.
  6. Imprimirlo - E.

Mis pronombres son El / El

Tim
fuente
Me gusta tu idea. +1
AB
No use input(), llamará eval(), use en raw_input()su lugar ... también su calificación no es la correcta, ya 90+que imprimirá la calificación ... Buse chr(74 - max(4, num))...
heemayl
bueno ... tu solución es buena y funcionará en python2 también ... solo cambia el input()a raw_input()para python2 ... eso es ...
heemayl
print chr(75-max(5,int('0'+raw_input('Enter the number: ')[:-1])))
heemayl
Luego hay que cambiar su código original too..your código modifed su forma actual, que está mal, aunque como python3no tiene raw_input().. me sugirió raw_input()para su uno inicial, como usted ha dicho que ejecutarlo utilizando python2..
heemayl
6

Aquí está mi solución bash semi- esotérica, que llena una matriz con 101 entradas y luego verifica la entrada del usuario contra ellas. Incluso para el uso en el mundo real, eso es razonable: si necesitara un rendimiento excelente, no estaría usando bash, y cien (más o menos) asignaciones siguen siendo rápidas. Pero dejaría de ser razonable si se extendiera a un rango mucho mayor (como un millón).

#!/usr/bin/env bash
p(){ for i in `seq $2 $3`; do g[$i]=$1; done; }
p A 90 100; p B 80 89; p C 70 79; p D 60 69; p F 0 59
while read -r n && [[ ! $n =~ ^[qQ] ]]; do echo ${g[$n]}; done

Ventajas:

  • No es realmente tan esotérico. Aunque es más largo que las soluciones más cortas, y no tan autodocumentado como las soluciones más largas ... es razonablemente autodocumentado , aunque todavía es decididamente pequeño.
  • Permite una fácil modificación para cambiar los rangos de calificación o agregar / eliminar calificaciones.
  • Se opera en un bucle y se cierra sobre q, quito cualquier cosa a partir de q/ Q.
  • Enumera primero los grados más altos, para ayudarlo a pensar en positivo. :)
  • Hmm, esto hace el trabajo, sigue teniendo sentido incluso después de mirarlo, y tiene las características esenciales. ¡Realmente podrías usar esto!

Desventajas

  • Te da una F cuando pones una entrada no numérica ... pero eso no es tan malo, ¿verdad? Si da un no número donde se necesita un número, ¡tal vez merezca una F!
  • La entrada ambigua, posiblemente octal, se trata como octal (ya que ges una matriz indexada unidimensional ). Como dice el viejo refrán, "¡No es un error, es una característica!" Bien quizás.
  • La entrada que está fuera del rango o que no es un número hace que se imprima una línea vacía. Sin embargo, no hay nada realmente malo en eso: le dice qué grado de letra corresponde a su entrada, y para la entrada incorrecta no hay una.
  • Pon un número negativo y ... bueno, llámalo huevo de pascua .
  • Todavía significativamente más largo que la solución de Python de Tim . Sí, realmente no puedo girar eso para parecer una ventaja.

Un poco genial, ¿eh? (Bueno, eso creo.)

Cómo funciona

  1. La pfunción p opula una matriz indexada numéricamente gde g rades, en índices que van desde su primer argumento hasta su segundo, con el valor (letra) dado en su tercer argumento.
  2. p se llama para cada grado de letra, para definir su rango numérico.
  3. Siga leyendo las entradas del usuario siempre que estén disponibles y no comiencen con q(o Q), verifique la gmatriz para qué grado de letra corresponde al número ingresado e imprima esa letra.
Eliah Kagan
fuente
¿Qué hay de este condicional? [[ $n =~ ^(0|[1-9]+[0-9]*)$ ]]
Helio
6

Después de hacerlo en Python 2 , decidí hacerlo en bash.

#! /bin/bash

read -p "Enter the number: " i
i=0$i
x=$((10#${i::-1}))
printf "\x$(printf %x $((11-($x>5?$x:5)+64)))\n"

Para ejecutarlo, guárdelo en un archivo (por ejemplo, grade.sh), hágalo ejecutable chmod +x grade.shy luego ejecútelo con ./grade.sh.

Esto es lo que verás:

Enter the number: 65
E

¿Como funciona esto?

  1. Tomar entrada - 65.
  2. Agregue un 0 al principio - 065(y lo 10#mantiene en la base 10).
  3. Eliminar el último carácter - 06.
  4. 75 restan ese número - 70.
  5. Convierte a una letra (A es 65, B es 66) - E.
  6. Imprimirlo - E.

Mis pronombres son El / El

Tim
fuente
Muy inteligente, bien hecho
kos
@kos gracias :) Dudo que funcione para el OP porque sus rangos probablemente no sean lo que publicó. Espero que sean por simplicidad.
Tim
5

Y aquí está mi versión awk:

awk '{
  if($_ <= 100 && $_ >= 0) {
      sub(/^([0-9]|[1-5][0-9])$/, "F", $_);
      sub(/^(6[0-9])$/, "D", $_);
      sub(/^(7[0-9])$/, "C", $_);
      sub(/^(8[0-9])$/, "B", $_);
      sub(/^(9[0-9]|100)$/, "A", $_);
      print
    }
    else {
      print "Only numbers between 0..100"
    }
}' -

o como una línea:

awk '{if($_ <= 100 && $_ >= 0) { sub(/^([0-9]|[1-5][0-9])$/, "F", $_); sub(/^(6[0-9])$/, "D", $_); sub(/^(7[0-9])$/, "C", $_); sub(/^(8[0-9])$/, "B", $_);sub(/^(9[0-9]|100)$/, "A", $_);   print} else { print "Only numbers between 0..100"}}' -
AB
fuente
4

Aquí hay otra respuesta "esotérica"

perl -E '
    print "number: "; 
    $n = <>; 
    say qw/A A B C D E F F F F F/[11-($n+1)/10]
       if $n=~/^\s*\d/ and 0<=$n and $n<=100
'

Explicación

  • perl -E: el -E, como -e, permite pasar una secuencia de comandos como argumento de línea de comando. Esta es una manera de ejecutar perl one-liners. A diferencia -e, -Etambién habilita todas las funciones opcionales (como say, que es básicamente una printcon una nueva línea final).
  • print "number: "; : solicita al usuario que ingrese un número.
  • $n = <>;: guarda ese número como $n.

El siguiente fragmento debe desglosarse un poco. qw/string/se evalúa en una lista hecha al dividir stringen espacios en blanco. Entonces, en qw/A A B C D E F F F F F/realidad es esta lista:

0 : A
1 : A
2 : B
3 : C
4 : D
5 : E
6 : F
7 : F
8 : F
9 : F
10 : F

Por lo tanto, say qw/A A B C D E F F F F F/[11-($n+1)/10]es equivalente a

my @F=("A","A","B","C","D","E","F","F","F","F","F");
print "$F[11-($n+1)/10]\n"

Ahora, Perl permite usar índices negativos para recuperar elementos contando desde el final de la matriz. Por ejemplo, $arrray[-1]imprimirá el último elemento de la matriz. Además, los índices de matriz de punto flotante (por ejemplo, 10.7) se truncan automáticamente al siguiente entero inferior (10.7, o 10.3 o lo que sea que se convierta en 10.)

El resultado de todo esto es que el índice 11-($n+1)/10siempre evalúa el elemento apropiado (grado) de la matriz.

Glenn Jackman
fuente
44
Las respuestas esotéricas son buenas, pero incluya una explicación.
Muru
1

Aunque solicitó una solución bash, creo que en Python, esto se puede hacer de una manera elegante y corta. Cubriendo ambos errores de manejo en caso de entrada incorrecta y la "conversión" de un número entre 0 y 100 en letras de la A a la F (o cualquier otra):

#!/usr/bin/env python3
try:
    n = int(input("number: ")); n = n if n>0 else ""
    print("FEDCBA"[[n>=f for f in [50,60,70,80,90,101]].count(True)])
except:
    print("invalid input")

Explicación

  1. Primero necesitamos obtener el número del usuario:

    n = int(input("number: "))
  2. Probamos este número para que sea válido para una serie de condiciones:

    n>=50, n>=60, n>=70, n>=80, n>=90

    Para cada una de estas pruebas, el resultado será Falseo True. Por lo tanto (comprimiendo el código un poco):

    [n>=f for f in [50,60,70,80,90]].count(True)]

    producirá una figura de 0a5

  3. Posteriormente, podemos usar esta figura como un índice para una cadena, para producir un carácter como salida, por ejemplo

    "ABCDEF"[3] 

    generará "D" (ya que el primer carácter = "A")

  4. Lo adicional 101a la lista es generar un error (Índice) en caso de que el número exceda 100, ya "ABCDEF"[6]que no existe. Lo mismo ocurre n = n if n>=0 else "", lo que creará un error (Valor) si se ingresa un número por debajo de 0
    En esos casos, así como si la entrada no es una cifra, el resultado será:

    invalid input

Los exámenes:

number: 10
F

number: 50
E

number: 60
D

number: 70
C

number: 80
B

number: 90
A

number: 110
invalid input

number: -10
invalid input

number: Monkey
invalid input
Jacob Vlijm
fuente