回答:
これまで見てきたように、この問題は、適度に長くある程度反復的で読みやすいソリューション(terdonとABの bashの回答)、および非常に短いが直感的ではなく、自己文書化がはるかに少ないソリューション(Timのpythonそして、bashの回答やグレン・ジャックマンの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ソリューションのコンパクト化された、まだかなり読みやすいバリアントよりもわずかに短いだけです。その方法に対する主な利点は次のとおりです。
((
))
動作の説明については以下を参照)。これらの3つの利点はすべて、この方法が構成数字を手動で調べるのではなく、数値データとしてユーザーの入力を使用するために発生します。
-e
)\
、エスケープ文字として解釈しないようにします(-r
)。-r
with を使用することをお勧めし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
しました(terdonの回答のように)。私はそれをして、その方法でもできることを示しました。グロブと正規表現は、テキストに一致するパターンを指定する2つの方法であり、どちらの方法でもこのアプリケーションに適しています。[[
=~
cutoffs
配列の最初の作成を除く)。端末入力が利用可能で、ユーザーが終了するように指示していない限り、数字を要求し、対応する文字のグレードを与えます。判断するとdo
... done
あなたがそれを望むようなコードの周りにあなたの質問に、それが見えます。q
またはの大文字と小文字を区別しないバリアントを受け入れますquit
。このスクリプトは、初心者には馴染みのないかもしれないいくつかの構造を使用します。以下に詳しく説明します。
continue
外側のwhile
ループの本体の残りの部分をスキップしたい場合は、continue
コマンドを使用します。これにより、ループの先頭に戻り、より多くの入力を読み取り、別の反復を実行します。
初めてこれを行うとき、私がいる唯一のループは外側のwhile
ループなのでcontinue
、引数なしで呼び出すことができます。(私は中だcase
構造、それの動作には影響しませんbreak
かをcontinue
。)
*) echo "I don't understand that number."; continue;;
ただし、2回目for
は、それ自体が外側のwhile
ループの内側にネストされている内側のループにいます。continue
引数なしで使用した場合、これは外側のループではなくcontinue 1
内側のfor
ループと同等になり、継続しwhile
ます。
((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }
そのため、その場合は、continue 2
代わりにbashが2番目のループを見つけて続行するようにします。
case
グローブ付きのラベル(ABのbash answerのように)数字がcase
どの文字グレードのビンに入るかを判断するために使用しません。しかし、ユーザーの入力を考慮する必要があるかどうかを判断するために使用しています。case
*( )@([1-9]*([0-9])|+(0))*( )
*( )[qQ]?([uU][iI][tT])*( )
*
これらはシェルグロブです。
)
任意の開口部により一致しないこと(
で、case
それが一致したときに実行されるコマンドからパターンを分離するための構文。;;
はcase
、特定の大文字と小文字を一致させるために実行するコマンドの終了を示すための構文です(実行後に後続のケースをテストしないでください)。通常のシェルグロビングでは*
、0個以上の文字、?
1つの文字、および[
]
括弧内の文字クラス/範囲に一致します。しかし、私は拡張グロビングを使用していますが、それはそれを超えています。拡張グロビングはbash
、対話的に使用する場合はデフォルトで有効になりますが、スクリプトを実行する場合はデフォルトで無効になります。shopt -s extglob
スクリプトの先頭にコマンドがそれをオンにします。
*( )@([1-9]*([0-9])|+(0))*( )
、数値入力をチェックし、次のシーケンスに一致します。
*( )
)。*(
)
構築物は、ここだけのスペースである、括弧内のパターンのゼロまたはそれ以上に一致します。-e
をread
有効にするフラグ用に記述されているため、ここでは心配していません。これは、ユーザーが左右の矢印キーを使用してテキスト内を前後に移動できるようにするためですが、通常、タブが文字どおりに入力されないという副作用があります。@(
)
いずれか(|
)の1つの出現():
[1-9]
)の後*(
)
に任意の数字のゼロ以上()が続きます([0-9]
)。+(
)
)0
。*( )
)、再び。*( )[qQ]?([uU][iI][tT])*( )
quitコマンドをチェックし、次のシーケンスに一致します:
*( )
)。q
またはQ
([qQ]
)。?(
)
:ゼロまたは1つのオカレンス():
u
またはU
([uU]
)に続くi
or I
([iI]
)に続くt
or T
([tT]
)。*( )
)、再び。あなたが正規表現ではなく、シェルグロブに対するユーザからの入力をテストする場合は、あなたは、このバージョンを使用することを好むが、同じ用途に働くかもしれない[[
と=~
(のようterdonの答え)の代わりcase
とグロブ延長しました。
#!/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
このアプローチの利点は次のとおりです。
この特定の場合、少なくとも2番目のパターンでは、quitコマンドをチェックする構文が少し単純です。私が設定することができたので、これはあるnocasematch
シェルオプションをし、すべてのケースでの変異体q
とquit
、自動的に覆われていました。
それがshopt -s nocasematch
コマンドの機能です。shopt -s extglob
コマンドは、このバージョンでは使用されませんグロブとして省略されています。
正規表現スキルは、bashの拡張機能の習熟度よりも一般的です。
=~
演算子の右側に指定されたパターンについては、これらの正規表現の仕組みを次に示します。
^\ *([1-9][0-9]*|0+)\ *$
、数値入力をチェックし、次のシーケンスに一致します。
^
)()。*
、適用された後置)スペース。通常\
、正規表現でスペースをエスケープする必要はありませんが、これは[[
構文エラーを防ぐために必要です。(
)
いずれか)または他の(|
)の:
[1-9][0-9]*
:ゼロ以外の数字([1-9]
)に続いて*
、任意の数字([0-9]
)のゼロ以上(、適用された接尾辞)。0+
:の1つ以上(+
、適用される接尾辞)0
。\ *
)。$
)()。case
テスト対象の式全体と一致するラベルとは異なり=~
、左側の式の一部が右側の式として指定されたパターンと一致する場合、trueを返します。理由はここにあり^
と$
アンカーは、ラインの開始と終了を指定し、ここで必要とされている、としてメソッドに表示されて何にも文法的に対応しないcase
とextglobs。
括弧を作るために必要とされる^
と$
の論理和にバインド[1-9][0-9]*
して0+
。それ以外の場合は、およびの選言で^[1-9][0-9]*
あり0+$
、ゼロ以外の数字で始まる入力または aで終わる入力0
(またはその両方に非数字が含まれている可能性があります)に一致します。
^\ *q(uit)?\ *$
quitコマンドをチェックし、次のシーケンスに一致します:
^
)。\ *
、上記の説明を参照)。q
。またはQ
、以来、shopt nocasematch
有効になっています。?
で、サブストリング((
)
)のゼロまたは1つのオカレンス(ポストフィックス):
u
、、、の順i
に続きt
ます。または、shopt nocasematch
有効になっている可能u
性がありますU
; 独立して、i
であってもよいですI
。そして独立して、t
かもしれT
。(すなわち、可能性はされないに限定uit
し、UIT
。)\ *
)。$
)。あなたはすでに基本的な考えを持っています。これをコーディングしたい場合bash
(Ubuntuおよび他のほとんどのLinuxのデフォルトのシェルであるため、これは合理的な選択です)、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 スクリプト 1ライナーがあります。それをbashにする必要がある場合は、シェルスクリプトとして同等のものも作成しました。
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()
あなたのグレーディングinstead..alsoが正しいようではない90+
グレードに印刷されますB
..useをchr(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()
、使用してそれを実行するように言われているとして、あなたの最初の1のためにpython2
...
ここに私のだセミ 101個のエントリを持つ配列を移入し、それらに対するユーザの入力をチェックし-esoteric bashのソリューションは、。現実的な使用であっても合理的です。優れたパフォーマンスが必要な場合、bashを使用することはなく、100(またはそれ以上)の割り当ては依然として高速です。しかし、もっと広い範囲(100万など)に拡張すると、合理的ではなくなります。
#!/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
のGの 3番目の引数で指定(文字)の値と、最初の引数からその第二の範囲のインデックスで、RADESを。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 one-linersを実行する方法です。とは異なり-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