Bagaimana cara menulis skrip shell untuk menetapkan nilai huruf ke rentang numerik?

19

Saya ingin membuat skrip yang akan meminta Anda untuk angka antara 0-100 dan kemudian memberi Anda nilai berdasarkan nomor tersebut.

Saya suka di 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
Pate Kuil
sumber

Jawaban:

20

Brevity vs. Readability: A Middle Ground

Seperti yang Anda lihat, masalah ini mengakui solusi yang cukup panjang dan agak berulang tetapi sangat mudah dibaca ( jawaban bash terdon dan AB ), serta solusi yang sangat pendek namun tidak intuitif dan jauh lebih sedikit mendokumentasikan diri sendiri (Tim python dan bash jawaban dan perl perl glenn jackman ). Semua pendekatan ini sangat berharga.

Anda juga dapat memecahkan masalah ini dengan kode di tengah kontinum antara kekompakan dan keterbacaan. Pendekatan ini hampir sama terbaca dengan solusi yang lebih panjang, dengan panjang yang lebih dekat dengan solusi esoterik yang kecil.

#!/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."

Dalam solusi bash ini, saya telah menyertakan beberapa baris kosong untuk meningkatkan keterbacaan, tetapi Anda dapat menghapusnya jika Anda menginginkannya lebih pendek.

Baris kosong disertakan, ini sebenarnya hanya sedikit lebih pendek dari sebuah compactified, varian masih cukup dibaca dari solusi pesta AB . Keuntungan utama metode ini adalah:

  • Ini lebih intuitif.
  • Lebih mudah untuk mengubah batas antara nilai (atau menambah nilai tambahan).
  • Secara otomatis menerima input dengan spasi awal dan akhir (lihat di bawah untuk penjelasan tentang cara (( ))kerjanya).

Ketiga keunggulan ini muncul karena metode ini menggunakan input pengguna sebagai data numerik daripada dengan secara manual memeriksa digit-konstituennya.

Bagaimana itu bekerja

  1. Baca input dari pengguna. Biarkan mereka menggunakan tombol panah untuk bergerak di dalam teks yang telah mereka masukkan ( -e) dan tidak menafsirkan \sebagai karakter melarikan diri ( -r).
    Skrip ini bukan solusi kaya fitur - lihat di bawah untuk penyempurnaan - tetapi fitur yang berguna hanya membuatnya dua karakter lebih lama. Saya sarankan selalu gunakan -rdengan read, kecuali Anda tahu Anda harus membiarkan pasokan pengguna \lolos.
  2. Jika pengguna menulis qatau Q, keluar.
  3. Buat array asosiatif ( ). Isi dengan nilai angka tertinggi yang terkait dengan setiap nilai huruf.declare -A
  4. Lingkari nilai huruf dari terendah ke tertinggi, memeriksa apakah angka yang disediakan pengguna cukup rendah untuk masuk dalam rentang angka setiap huruf.
    Dengan (( ))evaluasi aritmatika, nama variabel tidak perlu diperluas $. (Dalam sebagian besar situasi lain, jika Anda ingin menggunakan nilai variabel sebagai ganti namanya, Anda harus melakukan ini .)
  5. Jika jatuh dalam kisaran, cetak grade dan keluar .
    Untuk singkatnya, saya menggunakan hubungan pendek dan operator ( &&) daripada if- then.
  6. Jika loop selesai dan tidak ada jangkauan yang cocok, anggap angka yang dimasukkan terlalu tinggi (lebih dari 100) dan beri tahu pengguna bahwa itu di luar jangkauan.

Bagaimana ini Berperilaku, dengan Masukan Aneh

Seperti solusi singkat lainnya yang dipasang, skrip itu tidak memeriksa input sebelum mengasumsikan bahwa itu adalah angka. Evaluasi aritmatika ( (( ))) secara otomatis menghapus spasi spasi awal dan akhir, jadi itu tidak masalah, tetapi:

  • Input yang tidak terlihat seperti angka sama sekali ditafsirkan sebagai 0.
  • Dengan input yang terlihat seperti angka (yaitu, jika dimulai dengan angka) tetapi berisi karakter yang tidak valid, skrip memancarkan kesalahan.
  • Input multi-digit dimulai dengan 0yang ditafsirkan sebagai di oktal . Misalnya, skrip akan memberi tahu Anda 77 adalah C, sementara 077 adalah D. Meskipun beberapa pengguna mungkin menginginkan ini, kemungkinan besar tidak dan ini dapat menyebabkan kebingungan.
  • Di sisi positifnya, ketika diberi ekspresi aritmatika, skrip ini secara otomatis menyederhanakannya dan menentukan tingkat huruf terkait. Misalnya, ia akan memberi tahu Anda 320/4 adalah B.

Versi Diperluas, Fitur Penuh

Karena alasan itu, Anda mungkin ingin menggunakan sesuatu seperti skrip yang diperluas ini, yang memeriksa untuk memastikan inputnya baik, dan menyertakan beberapa perangkat tambahan lainnya.

#!/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

Ini masih merupakan solusi yang cukup kompak.

Fitur apa yang ditambahkan ini?

Poin kunci dari skrip yang diperluas ini adalah:

  • Validasi input. Script terdon memeriksa input dengan , jadi saya menunjukkan cara lain, yang mengorbankan beberapa keringkasan tetapi lebih kuat, memungkinkan pengguna untuk memasukkan spasi awal dan akhir dan menolak untuk mengizinkan ekspresi yang mungkin atau mungkin tidak dimaksudkan sebagai oktal (kecuali nol) .if [[ ! $response =~ ^[0-9]*$ ]] ...
  • Saya telah menggunakan casedengan diperpanjang globbing bukan [[dengan =~ ekspresi yang cocok reguler operator (seperti dalam jawaban Terdon ini ). Saya melakukan itu untuk menunjukkan bahwa (dan bagaimana) itu juga dapat dilakukan dengan cara itu. Gumpalan dan regexps adalah dua cara menentukan pola yang cocok dengan teks, dan metode mana pun baik untuk aplikasi ini.
  • Seperti skrip bash AB , saya telah menyertakan semuanya dalam lingkaran luar (kecuali pembuatan awal cutoffsarray). Ia meminta angka dan memberikan nilai huruf yang sesuai selama input terminal tersedia dan pengguna belum menyuruhnya untuk berhenti. Dilihat oleh do... di donesekitar kode dalam pertanyaan Anda, sepertinya Anda menginginkannya.
  • Agar mudah berhenti, saya menerima varian case-insensitive qatau quit.

Script ini menggunakan beberapa konstruksi yang mungkin asing bagi pemula; mereka dirinci di bawah ini.

Penjelasan: Penggunaan continue

Ketika saya ingin melewati sisa tubuh whileloop luar , saya menggunakan continueperintah. Ini membawanya kembali ke atas loop, untuk membaca lebih banyak input dan menjalankan iterasi lain.

Pertama kali saya melakukan ini, satu-satunya loop saya di adalah whileloop luar , jadi saya bisa menelepon continuetanpa argumen. (Saya dalam casekonstruksi, tetapi itu tidak mempengaruhi operasi breakatau continue.)

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

Namun, kedua kalinya saya berada di forloop dalam yang bersarang di dalam whileloop luar . Jika saya menggunakan continuetanpa argumen, ini akan sama dengan continue 1dan akan melanjutkan forloop dalam, bukan whileloop luar .

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

Jadi dalam hal itu, saya gunakan continue 2untuk membuat bash find dan melanjutkan loop kedua sebagai gantinya.

Penjelasan: caseLabel dengan Glob

Saya tidak menggunakan caseuntuk mencari tahu mana-huruf bin angka jatuh ke (seperti dalam AB jawaban pesta ). Tapi saya gunakan caseuntuk memutuskan apakah input pengguna harus dipertimbangkan:

  • nomor yang valid, *( )@([1-9]*([0-9])|+(0))*( )
  • perintah keluar, *( )[qQ]?([uU][iI][tT])*( )
  • hal lain (dan dengan demikian input tidak valid), *

Ini adalah shell shell .

  • Setiap diikuti oleh )yang tidak cocok dengan pembukaan apa pun (, yang merupakan casesintaks untuk memisahkan pola dari perintah yang dijalankan saat dicocokkan.
  • ;;adalah casesintaks untuk menunjukkan akhir perintah untuk menjalankan untuk pertandingan kasus paticular (dan bahwa tidak ada kasus berikutnya harus diuji setelah menjalankannya).

Globase shell biasa menyediakan *untuk mencocokkan dengan nol atau lebih karakter, ?untuk mencocokkan dengan tepat satu karakter, dan kelas / rentang karakter dalam [ ]kurung. Tapi saya menggunakan globbing diperpanjang , yang melampaui itu. Perpanjangan globbing diaktifkan secara default saat menggunakan secara bashinteraktif, tetapi dinonaktifkan secara default saat menjalankan skrip. The shopt -s extglobperintah di atas script menyala itu.

Penjelasan: Extended Globbing

*( )@([1-9]*([0-9])|+(0))*( ), yang memeriksa input numerik , cocok dengan urutan:

  • Nol atau lebih banyak spasi ( *( )). The *( )pertandingan konstruk nol atau lebih pola dalam kurung, yang di sini hanya spasi.
    Sebenarnya ada dua jenis spasi putih horizontal, spasi, dan tab, dan sering diinginkan juga untuk mencocokkan tab. Tapi saya tidak khawatir tentang itu di sini, karena skrip ini ditulis untuk input manual, interaktif, dan -ebendera untuk readmemungkinkan GNU readline. Ini agar pengguna dapat bergerak bolak-balik dalam teks mereka dengan tombol panah kiri dan kanan, tetapi memiliki efek samping yang umumnya mencegah tab masuk secara harfiah.
  • Satu kemunculan ( @( )) dari salah satu ( |):
    • Digit bukan nol ( [1-9]) diikuti oleh nol atau lebih ( *( )) dari setiap digit ( [0-9]).
    • Satu atau lebih ( +( )) dari 0.
  • Nol atau lebih banyak spasi ( *( )), lagi.

*( )[qQ]?([uU][iI][tT])*( ), yang memeriksa perintah keluar , cocok dengan urutan:

  • Nol atau lebih banyak spasi ( *( )).
  • qatau Q( [qQ]).
  • Opsional - yaitu, nol atau satu kejadian ( ?( )) - dari:
    • uatau U( [uU]) diikuti oleh iatau I( [iI]) diikuti oleh tatau T( [tT]).
  • Nol atau lebih banyak spasi ( *( )), lagi.

Varian: Memvalidasi Input dengan Ekspresi Reguler Diperpanjang

Jika Anda lebih suka menguji input pengguna terhadap ekspresi reguler daripada glob shell, Anda mungkin lebih suka menggunakan versi ini, yang berfungsi sama tetapi menggunakan [[dan =~(seperti dalam jawaban terdon ) alih-alih casedan globbing diperpanjang.

#!/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

Kemungkinan keuntungan dari pendekatan ini adalah:

  • Dalam kasus khusus ini, sintaks sedikit lebih sederhana, setidaknya dalam pola kedua, di mana saya memeriksa perintah berhenti. Ini karena saya dapat mengatur nocasematchopsi shell, dan kemudian semua varian case qdan quitdibahas secara otomatis.

    Itulah yang dilakukan shopt -s nocasematchperintah. The shopt -s extglobperintah dihilangkan sebagai globbing tidak digunakan dalam versi ini.

  • Keterampilan berekspresi reguler lebih umum daripada kemahiran dalam extglobs bash.

Penjelasan: Ekspresi Reguler

Adapun pola yang ditentukan di sebelah kanan =~operator, inilah cara kerja ekspresi reguler itu.

^\ *([1-9][0-9]*|0+)\ *$, yang memeriksa input numerik , cocok dengan urutan:

  • Awal - yaitu, tepi kiri - garis ( ^).
  • Nol atau lebih ( *, diterapkan postfix) spasi. Sebuah ruang biasanya tidak perlu \-disingkirkan dalam ekspresi reguler, tetapi ini diperlukan [[untuk mencegah kesalahan sintaksis.
  • A substring ( ( )) yang merupakan salah satu atau yang lain ( |) dari:
    • [1-9][0-9]*: digit bukan nol ( [1-9]) diikuti oleh nol atau lebih ( *, diterapkan pada postfix) setiap digit ( [0-9]).
    • 0+: satu atau lebih ( +, postfix yang diterapkan) dari 0.
  • Nol atau lebih banyak spasi ( \ *), seperti sebelumnya.
  • Akhir - yaitu, tepi kanan - dari garis ( $).

Tidak seperti caselabel, yang cocok dengan seluruh ekspresi yang diuji, =~mengembalikan true jika ada bagian dari ekspresi kiri yang cocok dengan pola yang diberikan sebagai ekspresi kanannya. Inilah sebabnya mengapa ^dan $jangkar, yang menentukan awal dan akhir baris, diperlukan di sini, dan tidak sesuai secara sintaksis dengan apa pun yang muncul dalam metode dengan casedan extglobs.

Tanda kurung diperlukan untuk membuat ^dan $mengikat pada disjungsi dari [1-9][0-9]*dan 0+. Kalau tidak, itu akan menjadi disjungsi dari ^[1-9][0-9]*dan 0+$, dan mencocokkan input apa pun yang dimulai dengan angka nol atau diakhiri dengan 0(atau keduanya, yang mungkin masih termasuk bukan digit di antaranya).

^\ *q(uit)?\ *$, yang memeriksa perintah keluar , cocok dengan urutan:

  • Awal baris ( ^).
  • Nol atau lebih banyak ruang ( \ *, lihat penjelasan di atas).
  • Surat itu q. Atau Q, sejak shopt nocasematchdiaktifkan.
  • Opsional - yaitu, nol atau satu kejadian (postfix ?) - dari substring ( ( )):
    • u, diikuti oleh i, diikuti oleh t. Atau, karena shopt nocasematchdiaktifkan umungkin U; secara mandiri, imungkin I; dan secara mandiri, tmungkin T. (Yaitu, kemungkinan tidak terbatas pada uitdan UIT.)
  • Nol atau lebih banyak ruang lagi ( \ *).
  • Akhir baris ( $).
Eliah Kagan
sumber
3
katakan yang sebenarnya..berapa banyak waktu yang dibutuhkan? ;)
heemayl
4
@ heemayl Saya tidak sepenuhnya yakin, karena saya menulisnya di banyak bagian kecil sepanjang hari (diikuti dengan pembacaan penuh dan pengeditan, sebelum memposting). Saya cukup yakin bahwa itu akan memakan waktu lebih lama daripada yang saya kira ketika saya mulai, meskipun, jika saya sudah memikirkan berapa lama waktu yang dibutuhkan. :)
Eliah Kagan
6
menulis lebih banyak dan lebih banyak, saya membutuhkan buku jawaban Anda.
Grijesh Chauhan
TL; DR tetapi tetap membuat saya tertawa!
Fabby
semuanya dari judul hingga penjelasan itu baik. Saya memahaminya pada mulanya tetapi saya membacanya lagi hanya karena saya ingin
Sumeet Deshmukh
23

Anda sudah memiliki ide dasar. Jika Anda ingin membuat kode ini bash(yang merupakan pilihan yang masuk akal karena ini adalah shell default pada Ubuntu dan sebagian besar Linux lainnya), Anda tidak dapat menggunakan casekarena tidak memahami rentang. Sebagai gantinya, Anda dapat menggunakan 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
sumber
4
Banyak dari -getes - tes itu dapat dihilangkan, mungkin, karena Anda gunakan elif. Dan tidak ada cinta untuk (( $response < X ))?
muru
2
@muru benar, terima kasih. Saya terjebak berpikir dalam rentang angka tetapi tidak ada alasan untuk itu. Adapun (( $response < X )), tentu saja, tetapi saya menemukan ini lebih jelas dan OP jelas baru untuk 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

dan versi yang lebih ringkas (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
sumber
1
Itu rentang karakter, tentunya? yaitu [0-59]berarti setiap karakter dari 0,1,2,3,4,5 atau 9 dan seterusnya. Saya tidak melihat bagaimana itu bisa berfungsi untuk nilai numerik .
steeldriver
3
Anda tidak harus menjadi FGITW setiap saat. Luangkan waktu Anda, tulis jawaban yang bagus. Lihatlah bagaimana cara terdon atau Eliah Kagan bekerja.
muru
@ AB Saya perhatikan bahwa solusi ini dapat dipersingkat, sebagian besar melalui perubahan gaya, sambil tetap cukup mudah dibaca. Brevity jarang menjadi pertimbangan terpenting, jadi saya tidak berpikir Anda harus mengubah apa yang Anda miliki dengan cara ini. Tetapi karena bentuk yang lebih ringkas tidak memakan banyak ruang, Anda dapat mempertimbangkan untuk menampilkannya juga, kalau-kalau beberapa pembaca menginginkan naskah pendek yang berfungsi dengan cara yang sama. (Jika Anda suka, silakan gunakan versi singkat saya, atau variasi apa pun di atasnya.)
Eliah Kagan
9

Semua instalasi Ubuntu memiliki Python, jadi di sini adalah skrip python satu baris. Jika Anda membutuhkannya di bash, saya juga menulis yang setara dengan skrip shell .

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

Untuk menjalankan, simpan dalam file (mis. grade.py) Dan kemudian jalankan di terminal dengan ini:

python grade.py

Inilah yang akan Anda lihat:

Enter the number: 65
E

Bagaimana cara kerjanya?

  1. Ambil input - 65.
  2. Tambahkan 0 ke awal - 065.
  3. Hapus karakter terakhir - 06.
  4. 75 kurangi angka itu - 70.
  5. Konversikan ke huruf (A adalah 65, B adalah 66) - E.
  6. Cetak itu - E.

Kata ganti saya adalah Dia / Dia

Tim
sumber
Saya suka ide Anda. +1
AB
Jangan gunakan input(), ia akan memanggil eval(), gunakan raw_input()instead..also gradasi Anda tidak benar karena 90+akan mencetak kelas B..use chr(74 - max(4, num))....
heemayl
baik..solusi Anda bagus dan akan bekerja di python2 juga.hanya ubah input()ke raw_input()untuk python2..thats it ..
heemayl
print chr(75-max(5,int('0'+raw_input('Enter the number: ')[:-1])))
heemayl
Maka Anda perlu mengubah kode asli Anda juga. Kode Anda dimodifikasi karena saat ini berdiri salah meskipun karena python3tidak memiliki raw_input().. saya menyarankan raw_input()untuk yang awal Anda seperti yang Anda katakan untuk menjalankannya menggunakan python2..
heemayl
6

Inilah solusi bash semi- esoterik saya , yang mengisi array dengan 101 entri dan kemudian memeriksa input pengguna terhadapnya. Bahkan untuk penggunaan di dunia nyata itu masuk akal - jika Anda membutuhkan kinerja yang sangat baik Anda tidak akan menggunakan bash, dan seratus (atau lebih) tugas masih cepat. Tapi itu akan berhenti masuk akal jika diperluas ke kisaran yang jauh lebih besar (seperti satu juta).

#!/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

Keuntungan:

  • Ini tidak terlalu esoteris. Meskipun lebih panjang dari solusi terpendek, dan tidak cukup mendokumentasikan diri sebagai solusi yang lebih lama ... itu cukup mendokumentasikan diri , sementara masih jelas di sisi kecil.
  • Ini memungkinkan modifikasi mudah untuk mengubah rentang nilai atau menambah / menghapus nilai.
  • Ini beroperasi dalam satu lingkaran dan berhenti pada q, quit, atau apa pun dimulai dengan q/ Q.
  • Daftarkan nilai yang lebih tinggi terlebih dahulu, untuk membantu Anda berpikir positif. :)
  • Hmm, ini pekerjaannya, tetap masuk akal bahkan setelah Anda melihatnya, dan memiliki fitur-fitur penting. Anda sebenarnya bisa menggunakan ini!

Kekurangan:

  • Ini memberi Anda F ketika Anda memasukkan input non-numerik ... tapi itu tidak terlalu buruk, bukan? Jika Anda memberikan nomor di mana nomor diperlukan, mungkin Anda layak mendapat nilai F!
  • Ambigu, mungkin input oktal diperlakukan sebagai oktal (karena gmerupakan array berindeks satu dimensi ). Seperti kata pepatah lama, "Ini bukan bug, ini fitur!" Ya, mungkin.
  • Input yang di luar jangkauan atau bukan angka menyebabkan garis kosong dicetak. Tidak ada yang benar-benar salah dengan itu: itu memberi tahu Anda apa yang sesuai dengan nilai surat sesuai dengan masukan Anda, dan untuk masukan yang salah tidak ada satu.
  • Masukkan angka negatif, dan itu ... yah, sebut saja telur paskah .
  • Masih jauh lebih lama dari solusi python Tim . Ya, saya tidak bisa benar-benar memutar itu agar terlihat seperti keuntungan.

Agak keren, ya? (Yah, kurasa begitu.)

Bagaimana itu bekerja

  1. The pfungsi p opulates array numerik diindeks gdari g rades, di indeks mulai dari argumen pertama untuk kedua, dengan (surat) nilai yang diberikan dalam argumen ketiga.
  2. p dipanggil untuk setiap nilai huruf, untuk menentukan rentang numeriknya.
  3. Terus baca input pengguna selama tersedia dan tidak dimulai dengan q(atau Q), memeriksa glarik yang tingkat hurufnya sesuai dengan angka yang dimasukkan, dan mencetak huruf itu.
Eliah Kagan
sumber
Bagaimana dengan persyaratan ini? [[ $n =~ ^(0|[1-9]+[0-9]*)$ ]]
Helio
6

Setelah membuatnya di Python 2 , saya memutuskan untuk membuatnya dalam 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"

Untuk menjalankannya, simpan di dalam file (mis. Grade.sh), buat itu dapat dieksekusi chmod +x grade.shdan kemudian jalankan bersama ./grade.sh.

Inilah yang akan Anda lihat:

Enter the number: 65
E

Bagaimana cara kerjanya?

  1. Ambil input - 65.
  2. Tambahkan 0 ke awal - 065(dan 10#basis 10).
  3. Hapus karakter terakhir - 06.
  4. 75 kurangi angka itu - 70.
  5. Konversikan ke huruf (A adalah 65, B adalah 66) - E.
  6. Cetak itu - E.

Kata ganti saya adalah Dia / Dia

Tim
sumber
Sangat pintar, bagus sekali
kos
@kos terima kasih :) Saya ragu ini akan bekerja untuk OP karena rentangnya mungkin bukan yang dia posting. Saya berharap itu untuk kesederhanaan.
Tim
5

Dan ini adalah versi awk saya:

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"
    }
}' -

atau sebagai one-liner:

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
sumber
4

Inilah jawaban "esoteris" yang lain

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
'

Penjelasan

  • perl -E: the -E, like -e, memungkinkan lewat skrip sebagai argumen baris perintah. Ini adalah cara untuk menjalankan perl one-liners. Tidak seperti itu -e, -Ejuga memungkinkan semua fitur opsional (seperti say, yang pada dasarnya adalah a printdengan trailing newline.).
  • print "number: "; : meminta pengguna untuk memasukkan nomor.
  • $n = <>;: simpan nomor itu sebagai $n.

Bit selanjutnya perlu dipecah sedikit. qw/string/mengevaluasi ke daftar yang dibuat dengan melanggar stringdi whitespace. Jadi, qw/A A B C D E F F F F F/sebenarnya daftar ini:

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

Karena itu, say qw/A A B C D E F F F F F/[11-($n+1)/10]sama dengan

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

Sekarang, Perl memungkinkan menggunakan indeks negatif untuk mengambil elemen yang menghitung dari akhir array. Misalnya, $arrray[-1]akan mencetak elemen terakhir dari array. Selain itu, indeks array titik mengambang (mis. 10.7) secara otomatis terpotong ke bilangan bulat bawah berikutnya (10.7, atau 10.3 atau apa pun yang menjadi 10.)

Hasil dari semua ini adalah bahwa indeks 11-($n+1)/10selalu mengevaluasi elemen (grade) array yang sesuai.

glenn jackman
sumber
4
Jawaban esoteris semuanya bagus, tetapi harap sertakan penjelasan.
muru
1

Meskipun Anda meminta solusi bash, saya pikir dengan python, ini bisa dilakukan dengan cara yang elegan. Meliputi kesalahan penanganan jika input yang salah dan "konversi" dari angka antara 0 dan 100 menjadi huruf dari A ke F (atau lainnya):

#!/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")

Penjelasan

  1. Pertama kita perlu mendapatkan nomor dari pengguna:

    n = int(input("number: "))
  2. Kami menguji nomor ini agar valid untuk sejumlah kondisi:

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

    Untuk setiap tes ini, hasilnya adalah salah satu Falseatau True. Oleh karena itu (mengompresi kode sedikit):

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

    akan menghasilkan angka dari 0hingga5

  3. Selanjutnya, kita dapat menggunakan gambar ini sebagai indeks untuk string, untuk menghasilkan karakter sebagai output, misalnya

    "ABCDEF"[3] 

    akan menampilkan "D" (sejak karakter pertama = "A")

  4. Tambahan 101ke daftar adalah untuk menghasilkan kesalahan (Indeks-) jika nomor melebihi 100, karena "ABCDEF"[6]tidak ada. Hal yang sama berlaku untuk n = n if n>=0 else "", yang akan membuat kesalahan (Nilai-) jika angka di bawah 0 dimasukkan
    Dalam kasus-kasus itu, serta jika input bukan angka, hasilnya adalah:

    invalid input

Tes:

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
Yakub Vlijm
sumber