Answers:
如您所见,此问题允许使用长度适中,有些重复但可读性强的解决方案(Terdon和AB的 bash答案),以及解决方案很短但不直观且自我记录少的解决方案(Tim的python)和bash答案以及glenn jackman的perl答案)。所有这些方法都是有价值的。
您还可以在紧凑性和可读性之间的连续过程中使用代码解决此问题。这种方法几乎与较长的解决方案一样可读,而长度却与较小的深奥的解决方案更接近。
#!/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."
在此bash解决方案中,我加入了一些空白行以增强可读性,但是如果您希望更短一些,可以将其删除。
空行在内,这比实际只略短一个紧凑化,仍然是相当可读变种的AB的bash的解决方案。与该方法相比,它的主要优点是:
(( ))工作原理的说明,请参见下文)。之所以出现这三个优点,是因为此方法使用用户的输入作为数字数据,而不是通过手动检查其组成数字。
-e)中移动,不要将其解释\为转义字符(-r)。-r与一起使用read,除非您知道需要让用户供应\转义。q或Q,请退出。declare -A)。用与每个字母等级相关的最高数字等级填充它。(( ))算术评估,不需要使用扩展变量名$。(在大多数其他情况下,如果要使用变量的值代替其名称,则必须执行此操作。)&&)而不是if- then。像发布的其他简短解决方案一样,该脚本在假定输入数字之前不会检查输入。算术评估((( )))自动删除开头和结尾的空格,所以这没问题,但是:
0被解释为在八进制。例如,脚本将告诉您77是C,而077是D。尽管有些用户可能想要这样做,但很可能不需要,这可能会引起混乱。由于这些原因,您可能想要使用类似于此扩展脚本的内容,该脚本进行检查以确保输入正确,并包括其他一些增强功能。
#!/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
这仍然是一个非常紧凑的解决方案。
此扩展脚本的关键点是:
if [[ ! $response =~ ^[0-9]*$ ]] ...case了扩展的globing,而不是[[使用了=~ 正则表达式匹配运算符(如terdon的answer)。我这样做是为了表明(以及如何)也可以这样做。globs和regexps是指定与文本匹配的模式的两种方法,对于该应用程序,这两种方法都适用。cutoffs数组的初始创建)。只要终端输入可用并且用户没有告诉它退出,它就会请求数字并给出相应的字母等级。根据问题代码中的do... 判断done,看起来就像您想要的那样。q或quit。该脚本使用了一些新手可能不熟悉的构造。他们在下面详细介绍。
continue当我想跳过外while循环的其余部分时,请使用continue命令。这使它回到循环的顶部,以读取更多输入并运行另一个迭代。
第一次执行此操作时,我所在的唯一循环是外部while循环,因此我可以continue不带任何参数地进行调用。(我在case构造中,但这不会影响break或的操作continue。)
*) echo "I don't understand that number."; continue;;
但是,第二次,我进入了一个内部for循环,该循环本身嵌套在外部while循环中。如果我continue不带任何参数使用,这将等同于continue 1并继续内部for循环而不是外部while循环。
((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }
因此,在这种情况下,我使用continue 2bash查找并继续执行第二个循环。
case带有标签的标签我不使用case找出哪些字母等级斌一批落入(如AB的bash的答案)。但我确实case决定是否应考虑用户的输入:
*( )@([1-9]*([0-9])|+(0))*( )*( )[qQ]?([uU][iI][tT])*( )*这些是贝壳球。
)没有任何开头的(,这是case的语法,用于将模式与匹配时运行的命令分开。;;是case的语法,用于指示要针对特定的大小写匹配运行的命令的结尾(并且在运行它们之后不应测试任何后续的大小写)。普通shell *匹配提供了零个或多个字符的?匹配,一个字符的精确匹配以及[ ]括号中的字符类/范围。但是我正在使用扩展的globlob,这还不止于此。bash交互式使用时,默认情况下会启用扩展的glob ,但是运行脚本时,默认情况下会禁用扩展的glob 。shopt -s extglob脚本顶部的命令将其打开。
*( )@([1-9]*([0-9])|+(0))*( ),它检查数字输入,与以下序列匹配:
*( ))。该*( )结构匹配括号中的零个或多个模式,这里仅是一个空格。-e标志read。这样一来,用户可以使用左右箭头键在其文本中来回移动,但是这样做的副作用是,通常会阻止按实际输入选项卡。@( ))之一出现(|):
[1-9]),后接零个或多个(*( ))任意数字([0-9])。+( ))0。*( )再次零个或多个空格()。*( )[qQ]?([uU][iI][tT])*( ),它检查quit命令,匹配以下序列:
*( ))。q或Q([qQ])。?( )):
u或U([uU])后跟i或I([iI])后跟t或T([tT])。*( )再次零个或多个空格()。如果您希望针对正则表达式而不是Shell Glob测试用户的输入,则您可能更喜欢使用此版本,该版本的工作原理相同,但是使用[[和=~(例如,在Terdon的答案中)代替case和扩展的Glob。
#!/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
这种方法可能的优点是:
在这种情况下,至少在第二种模式中,我检查quit命令的语法要简单一些。这是因为我能够设置nocasematchshell选项,然后将所有案件的变种q,并quit会自动覆盖。
这就是shopt -s nocasematch命令的作用。该shopt -s extglob命令被省略,因为此版本未使用通配符。
在bash的extglob中,正则表达技能比熟练程度更普遍。
至于在=~运算符右侧指定的模式,以下是这些正则表达式的工作方式。
^\ *([1-9][0-9]*|0+)\ *$,它检查数字输入,与以下序列匹配:
^)的起点,即左边缘。*,应用后缀)空格。通常不需要\在正则表达式中转义空格,但这是[[防止语法错误所必需的。( )),它是以下其中一个或另一个(|):
[1-9][0-9]*:一个非零数字([1-9]),后跟*任意一个数字()的零个或多个(,应用后缀[0-9])。0+:的一个或多个(+应用后缀)0。\ *与以前一样,零个或多个空格()。$)的末端,即右边缘。与case标签不同,标签与要测试的整个表达式匹配,=~如果其左侧表达式的任何部分与作为其右侧表达式给出的模式匹配,则返回true。这就是为什么在这里需要^and $锚点(指定行的开始和结尾),并且在语法上不对应于with case和extglobs 方法中出现的任何内容。
需要括号,使^和$结合的脱节[1-9][0-9]*和0+。否则会使的析取^[1-9][0-9]*和0+$,并匹配任何输入开始以非零的数字或与结束0(或两者,这可能仍然包括之间的非数字)。
^\ *q(uit)?\ *$,它检查quit命令,匹配以下序列:
^)。\ *,请参见上面的说明)。q。或Q,因为shopt nocasematch已启用。?)子字符串(( ))出现零次或一次(后缀):
u,i其次是t。或者,由于shopt nocasematch启用u可能是U;独立地,i可能是I;独立地t可能是T。(即,可能性并不限于uit和UIT)。\ *)。$)。您已经有了基本的想法。如果要使用此代码bash(这是一个合理的选择,因为它是Ubuntu和大多数其他Linux上的默认shell),则不能使用,case因为它不了解范围。相反,您可以使用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
-ge测试可以消除,据推测,由于您使用elif。没有爱(( $response < X ))吗?
(( $response < X )),当然,但是我发现它更清晰了,OP显然是bash脚本的新成员。
#!/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
以及更紧凑的版本(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
[0-59]表示0、1、2、3、4、5或9中的任何字符,依此类推。我看不到它如何适用于数值。
Ubuntu的所有安装都有Python,因此这里是一个python 脚本。如果您需要将它放在bash中,我也将等效代码编写为shell脚本。
print (chr(75-max(5,int('0'+raw_input('Enter the number: ')[:-1]))))
要运行,请将其保存在文件中(例如grade.py),然后在终端中运行以下命令:
python grade.py
这是您将看到的:
Enter the number: 65
E
这是如何运作的?
65。065。06。70。E。E。我的代词是他/他
input(),它会调用eval(),而是使用.. raw_input()90+Bchr(74 - max(4, num))
input()来raw_input()进行python2..thats它..
print chr(75-max(5,int('0'+raw_input('Enter the number: ')[:-1])))
python3没有raw_input()。.我建议raw_input()您使用第一个初始代码,因为您告诉过要使用python2..
这是我的半深奥bash解决方案,它用101个条目填充一个数组,然后根据它们检查用户输入。即使是在现实世界中使用,这也是合理的-如果您需要出色的性能,那么您就不会使用bash,并且一百个(或大约)任务仍然很快速。但是,如果扩展到更大的范围(例如一百万),它将不再是合理的。
#!/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
优点:
q,quit或任何开始q/ Q。缺点:
g它是一维索引数组)。俗话说:“这不是错误,而是功能!” 也许。有点酷吧?(嗯,我是这样认为的。)
p函数p opulates一个数字索引阵列g的克拉迪斯,在索引范围从它的第一个参数的第二,在其第三个参数给出的(字母)值。p 每个字母等级都会调用,以定义其数字范围。q(或Q)开头,请检查g字母等级与输入数字相对应的数组,然后打印该字母。[[ $n =~ ^(0|[1-9]+[0-9]*)$ ]]
在Python 2中制作之后,我决定在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"
要运行,请将其保存在文件(例如grade.sh)中,使其使用可执行,chmod +x grade.sh然后使用运行./grade.sh。
这是您将看到的:
Enter the number: 65
E
这是如何运作的?
65。065(并10#使其以10为底)。06。70。E。E。我的代词是他/他
这是我的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"
}
}' -
或单线:
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"}}' -
这是另一个“神秘的”答案
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
'
perl -E:和-E一样-e,允许将脚本作为命令行参数传递。这是运行perl单行代码的一种方法。与不同-e,-E它还启用所有可选功能(例如say,基本上是print带有尾随换行符的)。print "number: "; :提示用户输入数字。$n = <>;:将该号码另存为$n。接下来的一点需要分解。qw/string/求值是通过string在空格处断开而制成的列表。因此,qw/A A B C D E F F F F F/实际上是此列表:
0 : A
1 : A
2 : B
3 : C
4 : D
5 : E
6 : F
7 : F
8 : F
9 : F
10 : F
因此,say qw/A A B C D E F F F F F/[11-($n+1)/10]相当于
my @F=("A","A","B","C","D","E","F","F","F","F","F");
print "$F[11-($n+1)/10]\n"
现在,Perl允许使用负索引来检索从数组末尾开始计数的元素。例如,$arrray[-1]将打印数组的最后一个元素。此外,浮点数组索引(例如10.7)会自动截断为下一个较低的整数(10.7或10.3或所有等于10的整数)。
所有这些的结果是索引11-($n+1)/10总是求值到数组的适当元素(等级)。
尽管您要求使用bash解决方案,但我认为在python中,这可以通过简洁的方式完成。涵盖了在输入错误的情况下处理错误以及将0到100之间的数字“转换”为A到F(或其他任何字母)的情况:
#!/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")
首先,我们需要从用户那里获取电话号码:
n = int(input("number: "))我们测试此号码在多种情况下是否有效:
n>=50, n>=60, n>=70, n>=80, n>=90
对于这些测试中的每一个,结果将为False或True。因此(稍微压缩一下代码):
[n>=f for f in [50,60,70,80,90]].count(True)]
将产生一个从0到5
随后,我们可以将此图用作字符串的索引,以产生一个字符作为输出,例如
"ABCDEF"[3]
将输出“ D”(因为第一个字符=“ A”)
该101列表的附加功能是在数量超出时生成(Index-)错误100,因为该数量"ABCDEF"[6]不存在。同样适用于n = n if n>=0 else "",如果输入的数字小于0,则将产生(Value-)错误。
在这些情况下,以及如果输入的不是数字,结果将是:
invalid input测试:
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