Jak napisać skrypt powłoki, aby przypisać oceny literowe do zakresów liczbowych?

19

Chcę stworzyć skrypt, który monitowałby o numer od 0-100, a następnie wystawił ocenę na podstawie liczby.

Chciałbym to w 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
Temple Pate
źródło

Odpowiedzi:

20

Zwięzłość a czytelność: środek

Jak widzieliście, ten problem dotyczy rozwiązań, które są umiarkowanie długie i nieco powtarzalne, ale bardzo czytelne ( odpowiedzi bash Terdona i AB ), a także te, które są bardzo krótkie, ale nieintuicyjne i znacznie mniej samok dokumentujące ( pyton Tima i odpowiedzi bash i perl glenn jackman ). Wszystkie te podejścia są cenne.

Możesz także rozwiązać ten problem za pomocą kodu w środku kontinuum między zwartością a czytelnością. To podejście jest prawie tak samo czytelne jak dłuższe rozwiązania, o długości bliższej małym, ezoterycznym rozwiązaniom.

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

W tym rozwiązaniu dodałem kilka pustych wierszy w celu zwiększenia czytelności, ale możesz je usunąć, jeśli chcesz, aby był jeszcze krótszy.

Puste linie włączone, to faktycznie tylko nieznacznie krótsza niż w compactified, wciąż dość czytelnej wersji z roztworem bash AB . Jego główne zalety w stosunku do tej metody to:

  • To jest bardziej intuicyjne.
  • Łatwiej jest zmienić granice między ocenami (lub dodać dodatkowe oceny).
  • Automatycznie akceptuje wprowadzanie ze spacjami wiodącymi i końcowymi (wyjaśnienie, jak to (( ))działa poniżej ).

Wszystkie te trzy zalety wynikają z tego, że metoda ta wykorzystuje dane wejściowe użytkownika jako dane liczbowe, a nie poprzez ręczne sprawdzenie cyfr składowych.

Jak to działa

  1. Przeczytaj dane wejściowe od użytkownika. Pozwól im używać klawiszy strzałek do poruszania się po wprowadzonym tekście ( -e) i nie interpretuj ich \jako znak zmiany znaczenia ( -r).
    Ten skrypt nie jest bogatym w funkcje rozwiązaniem - udoskonalenie znajduje się poniżej - ale te przydatne funkcje wydłużają go o dwa znaki. Zalecam zawsze używać -rz read, chyba że wiesz, że musisz pozwolić użytkownikowi na \ucieczkę.
  2. Jeśli użytkownik napisał qlub Q, wyjdź.
  3. Załóż asocjacyjną tablicę ( declare -A). Wypełnij ją najwyższą oceną numeryczną związaną z każdą oceną literową.
  4. Pętle przechodź między literami od najniższej do najwyższej, sprawdzając, czy liczba podana przez użytkownika jest wystarczająco niska, aby mieściła się w zakresie liczbowym każdej litery.
    Przy (( ))obliczaniu arytmetycznym nazwy zmiennych nie muszą być rozszerzane o $. (W większości innych sytuacji, jeśli chcesz użyć wartości zmiennej zamiast jej nazwy, musisz to zrobić .)
  5. Jeśli mieści się w zakresie, wydrukuj ocenę i wyjdź .
    Dla zwięzłości używam zwarcia i operatora ( &&) zamiast if- then.
  6. Jeśli pętla zakończy się i żaden zakres nie zostanie dopasowany, załóż, że wprowadzona liczba jest zbyt wysoka (ponad 100) i powiedz użytkownikowi, że jest poza zasięgiem.

Jak to się dzieje, z dziwnym wkładem

Podobnie jak inne opublikowane krótkie rozwiązania, skrypt nie sprawdza danych wejściowych przed założeniem, że jest liczbą. Arytmetyczna oceny ( (( ))) automatycznie pozbawia początkowe i końcowe spacje, więc to nie ma problemu, ale:

  • Dane wejściowe, które wcale nie wyglądają jak liczba, są interpretowane jako 0.
  • Przy wprowadzeniu, które wygląda jak liczba (tzn. Jeśli zaczyna się cyfrą), ale zawiera nieprawidłowe znaki, skrypt emituje błędy.
  • Multi-cyfrowy wejście zaczynając 0jest interpretowane jako w ósemkowym . Na przykład skrypt powie Ci, że 77 to C, a 077 to D. Chociaż niektórzy użytkownicy mogą tego chcieć, najprawdopodobniej tego nie robią i mogą powodować zamieszanie.
  • Z drugiej strony, po otrzymaniu wyrażenia arytmetycznego, ten skrypt automatycznie upraszcza go i określa powiązaną ocenę literową. Na przykład powie ci, że 320/4 to B.

Rozszerzona, w pełni funkcjonalna wersja

Z tych powodów możesz chcieć użyć czegoś takiego jak ten rozszerzony skrypt, który sprawdza, czy dane wejściowe są dobre, i zawiera kilka innych ulepszeń.

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

To wciąż dość kompaktowe rozwiązanie.

Jakie funkcje to dodaje?

Kluczowe punkty tego rozszerzonego skryptu to:

  • Sprawdzanie poprawności danych wejściowych. Skrypt terdona sprawdza dane wejściowe za pomocą , więc pokazuję inny sposób, który poświęca pewną zwięzłość, ale jest bardziej niezawodny, pozwalając użytkownikowi na wprowadzanie spacji wiodących i końcowych oraz odmawiając zezwolenia na wyrażenie, które może, ale nie musi być wyrażeniem ósemkowym (chyba że zero) .if [[ ! $response =~ ^[0-9]*$ ]] ...
  • Używałem casez rozszerzonym globbing zamiast [[z =~ dopasowywania wyrażeń regularnych operatora (jak w odpowiedzi terdon za ). Zrobiłem to, aby pokazać, że (i jak) można to zrobić w ten sposób. Globi i wyrażenia regularne to dwa sposoby określania wzorców pasujących do tekstu, a każda z tych metod jest odpowiednia dla tej aplikacji.
  • Podobnie jak skrypt bash AB , wszystko zamknąłem w zewnętrznej pętli (oprócz początkowego utworzenia cutoffstablicy). Żąda liczb i podaje odpowiednie stopnie literowe, o ile dostępne jest wejście terminala, a użytkownik nie kazał mu wyjść. Sądząc po do... donewokół kodu w twoim pytaniu, wygląda na to, że tego chcesz.
  • Aby ułatwić rzucanie, akceptuję każdy wariant qlub bez rozróżniania wielkości liter quit.

Ten skrypt wykorzystuje kilka konstrukcji, które mogą być nieznane nowicjuszom; są wyszczególnione poniżej.

Objaśnienie: Zastosowanie continue

Kiedy chcę pominąć resztę ciała zewnętrznej whilepętli, używam continuepolecenia. Sprowadza to go z powrotem na szczyt pętli, aby przeczytać więcej danych wejściowych i uruchomić kolejną iterację.

Gdy robię to po raz pierwszy, jedyną pętlą, w której jestem, jest whilepętla zewnętrzna , więc mogę wywoływać continuebez argumentów. (Jestem w casekonstrukcji, ale to nie wpływa na działanie breaklub continue.)

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

Jednak po raz drugi jestem w wewnętrznej forpętli, która sama jest zagnieżdżona w zewnętrznej whilepętli. Gdybym użył continuebez argumentu, byłoby to równoważne continue 1i kontynuowałoby forpętlę wewnętrzną zamiast whilepętli zewnętrznej .

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

Więc w takim przypadku używam, continue 2aby bash znalazł i kontynuował drugą pętlę.

Objaśnienie: caseEtykiety z kulami

Nie używać case, aby dowiedzieć się, jaka litera gatunek bin numer wpada (jak w AB bash odpowiedź ). Ale casedecyduję, czy należy wziąć pod uwagę wkład użytkownika:

  • ważny numer, *( )@([1-9]*([0-9])|+(0))*( )
  • polecenie wyjścia, *( )[qQ]?([uU][iI][tT])*( )
  • wszystko inne (a zatem nieprawidłowe dane wejściowe), *

To są kule globu .

  • Po każdym następuje znak, )który nie jest dopasowany żadnym otworem (, który jest caseskładnią służącą do oddzielenia wzorca od poleceń uruchamianych podczas dopasowywania.
  • ;;to caseskładnia wskazująca koniec komend, które mają być uruchamiane w typowym dopasowaniu wielkości liter (i że żadne kolejne przypadki nie powinny być testowane po ich uruchomieniu).

Zwykłe globowanie powłoki zapewnia *dopasowanie zero lub więcej znaków, ?dopasowanie dokładnie jednego znaku oraz klas znaków / zakresów w [ ]nawiasach. Ale używam rozszerzonego globowania , które wykracza poza to. Rozszerzone globowanie jest domyślnie włączone, gdy jest używane bashinteraktywnie, ale jest domyślnie wyłączone podczas uruchamiania skryptu. shopt -s extglobKomenda na górze skryptu włącza go.

Objaśnienie: Rozszerzone globowanie

*( )@([1-9]*([0-9])|+(0))*( ), który sprawdza wprowadzanie numeryczne , dopasowuje sekwencję:

  • Zero lub więcej spacji ( *( )). Te *( )mecze konstrukt zero lub więcej z wzorca w nawiasach, co tutaj jest tylko przestrzeń.
    W rzeczywistości istnieją dwa rodzaje poziomych białych znaków, spacje i tabulatory i często pożądane jest również dopasowanie tabulatorów. Ale nie martwię się o to tutaj, ponieważ ten skrypt jest napisany do ręcznego, interaktywnego wprowadzania i -eflagi readumożliwiającej readline GNU. Dzieje się tak, aby użytkownik mógł poruszać się w tekście w przód iw tył za pomocą klawiszy strzałek w lewo i w prawo, ale ma to efekt uboczny polegający na tym, że tabulatory nie mogą być wprowadzane dosłownie.
  • Jedno wystąpienie ( @( )) albo ( |):
    • Niezerowa cyfra ( [1-9]), po której następuje zero lub więcej ( *( )) dowolnej cyfry ( [0-9]).
    • Jeden lub więcej ( +( )) z 0.
  • Zero lub więcej spacji ( *( )) ponownie.

*( )[qQ]?([uU][iI][tT])*( ), który sprawdza komendę quit , dopasowuje sekwencję:

  • Zero lub więcej spacji ( *( )).
  • qlub Q( [qQ]).
  • Opcjonalnie - tj. Zero lub jedno wystąpienie ( ?( )) - z:
    • ulub U( [uU]), po której następuje ilub I( [iI]), po której następuje tlub T( [tT]).
  • Zero lub więcej spacji ( *( )) ponownie.

Wariant: Sprawdzanie poprawności danych wejściowych za pomocą rozszerzonego wyrażenia regularnego

Jeśli wolisz przetestować dane wejściowe użytkownika na podstawie wyrażenia regularnego zamiast globu powłoki, możesz użyć tej wersji, która działa tak samo, ale używa [[i =~(jak w odpowiedzi Terdona ) zamiast caserozszerzonego globowania.

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

Możliwe zalety tego podejścia to:

  • W tym konkretnym przypadku składnia jest nieco prostsza, przynajmniej w drugim wzorze, w którym sprawdzam komendę quit. Jest tak, ponieważ byłem w stanie ustawić nocasematchopcję powłoki, a następnie wszystkie warianty przypadków qi quitzostały pokryte automatycznie.

    To właśnie shopt -s nocasematchrobi polecenie. shopt -s extglobKomenda zostanie pominięta jako globbing nie jest używane w tej wersji.

  • Umiejętności wyrażania regularnego są bardziej powszechne niż biegłość w ekstlobach basha.

Objaśnienie: Wyrażenia regularne

Jeśli chodzi o wzorce określone po prawej stronie =~operatora, oto jak działają te wyrażenia regularne.

^\ *([1-9][0-9]*|0+)\ *$, który sprawdza wprowadzanie numeryczne , dopasowuje sekwencję:

  • Początek - tj. Lewa krawędź - linii ( ^).
  • Zero lub więcej ( *, zastosowanych postfiksów) spacji. Spacja zwykle nie wymaga \przeszukiwania w wyrażeniu regularnym, ale jest to konieczne, [[aby zapobiec błędowi składni.
  • Podłańcuch ( ( )), który jest jednym lub drugim ( |) z:
    • [1-9][0-9]*: niezerowa cyfra ( [1-9]), po której następuje zero lub więcej ( *stosowana postfiks) dowolnej cyfry ( [0-9]).
    • 0+: jeden lub więcej ( +, zastosowany postfiks) z 0.
  • Zero lub więcej spacji ( \ *), jak poprzednio.
  • Koniec - tj. Prawa krawędź - linii ( $).

W przeciwieństwie do caseetykiet, które pasują do całego testowanego wyrażenia, =~zwraca wartość true, jeśli jakakolwiek część jego wyrażenia po lewej stronie odpowiada wzorowi podanemu jako wyrażenie po prawej stronie. Właśnie dlatego potrzebne są tutaj kotwice ^i $, określające początek i koniec linii, i nie odpowiadają składniowo niczego, co pojawia się w metodzie z casei extglobami.

Nawiasy są potrzebne do utworzenia ^i $wiązania rozłączności z [1-9][0-9]*i 0+. W przeciwnym razie byłoby to rozłączenie ^[1-9][0-9]*i 0+$, i pasowałoby do każdego wejścia zaczynającego się od niezerowej cyfry lub kończącego się na 0(lub oba, które nadal mogą zawierać między nimi cyfry niebędące cyframi).

^\ *q(uit)?\ *$, który sprawdza komendę quit , dopasowuje sekwencję:

  • Początek linii ( ^).
  • Zero lub więcej spacji ( \ *patrz powyższe objaśnienie).
  • List q. Lub Q, ponieważ shopt nocasematchjest włączony.
  • Opcjonalnie - tzn. Zero lub jedno wystąpienie (postfiks ?) - podłańcucha ( ( )):
    • u, a następnie i, a następnie t. Lub, ponieważ shopt nocasematchjest włączony umoże być U; niezależnie imoże być I; i niezależnie tmogą być T. (To znaczy, możliwości nie są ograniczone do uiti UIT.)
  • Zero lub więcej spacji ponownie ( \ *).
  • Koniec linii ( $).
Eliah Kagan
źródło
3
powiedz mi prawdę ... ile czasu to zajęło? ;)
heemayl
4
@ heemayl Nie jestem do końca pewien, ponieważ napisałem go w wielu małych częściach w ciągu dnia (po czym nastąpiło pełne przeczytanie i edycja, tuż przed opublikowaniem). Jestem jednak całkiem pewien, że skończyło się to dłużej, niż myślałem, kiedy zaczynałem, choć zastanawiałem się, ile to zajmie. :)
Eliah Kagan
6
pisz coraz więcej, potrzebuję książki twoich odpowiedzi.
Grijesh Chauhan
TL; DR, ale i tak mnie rozśmieszył!
Fabby,
wszystko od tytułu do wyjaśnienia jest dobre. Zrozumiałem to za pierwszym razem, ale przeczytałem to ponownie tylko dlatego, że chciałem
Sumeet Deshmukh
23

Masz już podstawowy pomysł. Jeśli chcesz to zakodować bash(co jest rozsądnym wyborem, ponieważ jest domyślną powłoką w Ubuntu i większości innych Linuksów), nie możesz użyć, caseponieważ nie rozumie zakresów. Zamiast tego możesz użyć 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
źródło
4
Wiele z tych -getestów można wyeliminować, prawdopodobnie, ponieważ ich używasz elif. I nie ma miłości (( $response < X ))?
muru
2
@muru prawda, dzięki. Utknąłem myśląc w zakresach liczbowych, ale nie było powodu. Co do tego (( $response < X )), oczywiście, ale uważam, że jest to jaśniejsze, a OP jest oczywiście nowością w skryptowaniu bash.
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

i bardziej kompaktowa wersja (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
źródło
1
Na pewno są to zakresy postaci? tzn. [0-59]oznacza dowolny znak z 0,1,2,3,4,5 lub 9 itd. Nie rozumiem, jak to może działać dla wartości liczbowych .
steeldriver
3
Nie musisz cały czas być FGITW. Nie spiesz się, pisz dobre odpowiedzi. Zobacz, jak działa terdon lub Eliah Kagan.
muru
@AB Zauważyłem, że to rozwiązanie można skrócić, głównie poprzez zmiany stylistyczne, pozostając wciąż dość czytelne. Zwięzłość rzadko jest najważniejszym czynnikiem, więc nie sądzę, że powinieneś zmienić to, co masz. Ponieważ jednak bardziej zwarta forma nie zajmuje dużo miejsca, możesz rozważyć jej wyświetlenie, na wypadek gdyby niektórzy czytelnicy chcieli krótszego skryptu, który działa w ten sam sposób. (Jeśli chcesz, skorzystaj z mojej skróconej wersji lub jakiejkolwiek jej wersji).
Eliah Kagan
9

Wszystkie instalacje Ubuntu mają Python, więc tutaj jest jeden linijka skryptu Python . Jeśli potrzebujesz tego w bashu, napisałem również odpowiednik jako skrypt powłoki .

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

Aby uruchomić, zapisz go w pliku (np. grade.py), A następnie uruchom w terminalu w ten sposób:

python grade.py

Oto, co zobaczysz:

Enter the number: 65
E

Jak to działa?

  1. Weź wkład - 65.
  2. Dodaj 0 na początku - 065.
  3. Usuń ostatni znak - 06.
  4. 75 odejmij tę liczbę - 70.
  5. Konwertuj na literę (A to 65, B to 66) - E.
  6. Wydrukuj to E.

Moje zaimki to On / On

Tim
źródło
Podoba mi się twój pomysł. +1
AB
Nie używaj input(), zadzwoni eval(), użyje raw_input()zamiast tego .. również twoja ocena jest nieprawidłowa, jak 90+wydrukuje ocenę .. Bużyj chr(74 - max(4, num))....
heemayl
well..your rozwiązanie jest dobre i będzie działać w python2 also..just zmiany wysokość input()do raw_input()dla python2..thats to ..
heemayl
print chr(75-max(5,int('0'+raw_input('Enter the number: ')[:-1])))
heemayl
Następnie musisz również zmienić swój pierwotny kod. Zmodyfikowany kod w obecnym stanie jest niepoprawny, ponieważ python3nie ma go raw_input(). Zasugerowałem raw_input()dla twojego początkowego kodu, ponieważ kazałeś go uruchomić przy użyciu python2...
heemayl
6

Oto moje semi- ezoteryczne rozwiązanie bash, które zapełnia tablicę 101 wpisami, a następnie sprawdza dane wejściowe użytkownika. Nawet do użytku w świecie rzeczywistym jest to rozsądne - gdybyś potrzebował doskonałej wydajności, nie używałbyś bash, a sto (lub mniej więcej) zadań wciąż jest szybkich. Ale przestałoby być rozsądne, gdyby rozszerzyć go na znacznie większy zasięg (np. Milion).

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

Zalety:

  • To nie jest tak ezoteryczne. Chociaż jest dłuższy niż najkrótsze rozwiązania i nie tak samo-dokumentujący jak dłuższe rozwiązania ... jest dość samo-dokumentujący , choć zdecydowanie zdecydowanie niewielki.
  • Umożliwia łatwą modyfikację w celu zmiany zakresów ocen lub dodawania / usuwania ocen.
  • To działa w pętli i zamykany na q, quitlub cokolwiek zaczynając q/ Q.
  • Wymienia najpierw wyższe stopnie, aby pomóc Ci myśleć pozytywnie. :)
  • Hmm, spełnia to zadanie, ma sens nawet po spojrzeniu na niego i ma podstawowe cechy. Naprawdę możesz tego użyć!

Niedogodności:

  • Daje ci F po wprowadzeniu danych nienumerycznych ... ale to nie jest takie złe, prawda? Jeśli podasz liczbę, która nie jest potrzebna, być może zasługujesz na F!
  • Niejednoznaczne, być może ósemkowe dane wejściowe są traktowane jako ósemkowe (ponieważ gjest to jednowymiarowa tablica indeksowana ). Jak mówi stare powiedzenie: „To nie jest błąd, to funkcja!” Być może.
  • Dane wejściowe, które są poza zakresem lub nie są liczbą, powodują wydrukowanie pustej linii. Nie ma w tym jednak nic złego: mówi, jaka ocena literowa odpowiada twojemu wprowadzeniu, a przy niewłaściwym wprowadzeniu nie ma takiego.
  • Wpisz liczbę ujemną i ... no cóż, nazwij to pisanką .
  • Nadal znacznie dłużej niż rozwiązanie Pytona Tima . Tak, naprawdę nie mogę tego przekręcić, żeby wydawało się to zaletą.

Trochę fajnie, co? (No cóż, myślę że tak.)

Jak to działa

  1. pFunkcja P opulates numerycznie indeksowaną go g Rades, w indeksy w zakresie od pierwszego argumentu do drugiego, z wartością (letter) podawana w trzecim argumentem.
  2. p jest wywoływany dla każdej klasy literowej w celu zdefiniowania jego zakresu liczbowego.
  3. Czytaj dalej dane wprowadzane przez użytkownika, o ile są one dostępne i nie zaczynają się od q(lub Q), sprawdzając gtablicę, dla której klasa liter odpowiada wprowadzonej liczbie, i drukuj tę literę.
Eliah Kagan
źródło
Co z tym warunkiem? [[ $n =~ ^(0|[1-9]+[0-9]*)$ ]]
Helio
6

Po zrobieniu go w Pythonie 2 , postanowiłem zrobić to w bashu.

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

Aby uruchomić, zapisz go w pliku (np. Grade.sh), ustaw go jako wykonywalny, chmod +x grade.sha następnie uruchom za pomocą ./grade.sh.

Oto, co zobaczysz:

Enter the number: 65
E

Jak to działa?

  1. Weź wkład - 65.
  2. Dodaj 0 na początku - 065(i 10#zachowuje bazę 10).
  3. Usuń ostatni znak - 06.
  4. 75 odejmij tę liczbę - 70.
  5. Konwertuj na literę (A to 65, B to 66) - E.
  6. Wydrukuj to E.

Moje zaimki to On / On

Tim
źródło
Bardzo sprytne, dobrze zrobione
kosztują
@kos dzięki :) Wątpię, żeby to zadziałało dla OP, ponieważ jego zakresy prawdopodobnie nie są tym, co opublikował. Oczekuję, że są one dla uproszczenia.
Tim
5

A oto moja wersja 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"
    }
}' -

lub jako jedna linijka:

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
źródło
4

Oto kolejna „ezoteryczna” odpowiedź

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
'

Wyjaśnienie

  • perl -E: the -E, like -e, pozwala przekazać skrypt jako argument wiersza poleceń. Jest to sposób na uruchomienie Perla One-Liners. W przeciwieństwie do -e, -Ewłącza również wszystkie opcjonalne funkcje (takie jak say, który jest w zasadzie printz końcowym znakiem nowej linii).
  • print "number: "; : poproś użytkownika o wprowadzenie numeru.
  • $n = <>;: zapisz ten numer jako $n.

Kolejny kawałek trzeba trochę rozbić. qw/string/tworzy listę utworzoną przez rozbicie stringna białe znaki. Tak więc qw/A A B C D E F F F F F/właściwie jest to lista:

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

Dlatego say qw/A A B C D E F F F F F/[11-($n+1)/10]jest równoważne z

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

Teraz Perl pozwala na stosowanie indeksów ujemnych do pobierania elementów zliczających z końca tablicy. Na przykład $arrray[-1]wydrukuje ostatni element tablicy. Ponadto indeksy tablic zmiennoprzecinkowych (np. 10.7) są automatycznie obcinane do następnej niższej liczby całkowitej (10.7 lub 10.3 lub cokolwiek innego, co staje się 10.)

Wynikiem tego wszystkiego jest to, że indeks 11-($n+1)/10zawsze ocenia odpowiedni element (stopień) tablicy.

Glenn Jackman
źródło
4
Ezoteryczne odpowiedzi są miłe, ale proszę o wyjaśnienie.
muru
1

Chociaż poprosiłeś o rozwiązanie bash, myślę, że w Pythonie, można to zrobić w elegancki sposób w skrócie. Obejmuje zarówno błędy obsługi w przypadku nieprawidłowego wprowadzenia, jak i „konwersję” liczby od 0 do 100 na litery od A do F (lub dowolne inne):

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

Wyjaśnienie

  1. Najpierw musimy uzyskać numer od użytkownika:

    n = int(input("number: "))
  2. Testujemy tę liczbę, aby była ważna dla wielu warunków:

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

    Dla każdego z tych testów, wynik będzie albo Falsealbo True. Dlatego (trochę kompresując kod):

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

    stworzy liczbę od 0do5

  3. Następnie możemy użyć tej liczby jako indeksu łańcucha, aby utworzyć znak jako wynik, np

    "ABCDEF"[3] 

    wyświetli „D” (ponieważ pierwszy znak = „A”)

  4. Dodatkową 101częścią listy jest generowanie błędu (indeksu) w przypadku przekroczenia liczby 100, ponieważ "ABCDEF"[6]nie istnieje. To samo dotyczy n = n if n>=0 else "", który spowoduje błąd (Wartość-), jeśli zostanie wprowadzona liczba poniżej 0.
    W takich przypadkach, a także jeśli dane wejściowe nie są liczbą, wynikiem będzie:

    invalid input

Testy:

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
źródło