Измерение скорости печати в терминал без ошибки


Я обычно не нравится мой код. Это всегда беспорядок. Я не могу критиковать, хотя мой собственный код, потому что я просто превратить его в очередную переделку. Я программирую немного лучше каждый год, но в этом году она практически не изменилась.

#!/bin/bash

RED='\e[101m'
NC='\033[0m' # No Color

lesson[1]="#!/bin/bash"
lesson[2]="#!/bin/bash"

lessons=${#lesson[@]}
current_lesson=1
speed=70

function start() {
        SECONDS=0 #restart timer

        reset_user_input
        string_to_type=${lesson[$1]};
        length_of_string=${#string_to_type}
        echo $string_to_type

        count=0
        while [ "$count" -ne "$length_of_string" ]; do
                checkCharacter
        done
        time_it_took=$SECONDS
        sec=60
        wpm=$((sec / time_it_took))
        wpm=$((wpm * length_of_string / 5))
        echo " "
        echo "speed: "$wpm
}

function checkCharacter() {
        IFS= read -r -s -n 1 user_input_char
        add_user_input $user_input_char

        if [ "$user_input_char" == " " ]; then
                add_user_input " "
                if [ "$user_input_char" == "${string_to_type:$count:1}" ]; then
                        printf " " 
                else
                        printf ${RED}" "${NC}
                fi
        else
                if [ "$user_input_char" == "${string_to_type:$count:1}" ]; then
                        printf $user_input_char
                else
                        printf ${RED}$user_input_char${NC}
                fi
        fi
    let count+=1
}

function check_correct() {
        if [ "$user_input" == "$string_to_type" ]; then
                return;
        else
                echo "too many mistakes, try again!"
                false;
        fi
}

function check_speed() {
        if [ "$wpm" -gt speed ]; then
                return;
        else
                echo "too slow, try again!"
                false
        fi
}


function start_lesson() {
        start $1
        if check_speed && check_correct; then
                echo "you succeeded!"
                echo " " # padding for every lesson
                return;
        fi
        echo " " # padding for every lesson
        false
}

function reset_user_input() {
        user_input=""
}

function add_user_input() {
        user_input=${user_input}$1
}

while [ "$current_lesson" -le "$lessons" ]; do
        echo "lesson:" $current_lesson
        until start_lesson $current_lesson; do : ; done;
        let current_lesson+=1
done


130
4
задан 29 января 2018 в 02:01 Источник Поделиться
Комментарии
2 ответа

Я думаю, что это очень хороший, чистый код. Давайте сделаем его лучше!

Последовательность

Консистенция очень помогает, делает код легче для понимания.


  • Некоторые функции по имени camelCaseдругие snake_case. Придерживаться одного шаблона.

  • Некоторые переменные называются SHOUT_CASEдругие snake_case. Придерживаться одного шаблона. Последнее предпочтительнее, потому что верхний регистр имен переменных обычно используются для системных переменных, как PATH и другие.

  • Абзацный отступ в основном 8 мест, за редким исключением. Использовать тот же везде.

Объявление переменной

Это хорошо для объявления глобальных констант в верхней части файла, где их легко увидеть.
То же самое не верно для переменных состояния, которые являются деталями реализации,
например current_lesson.
Этой переменной было бы лучше, чтобы инициализировать прямо перед вам это нужно.

Итерации по массивам

Вместо подсчета петли над lessonмассив,
есть более идиоматические подход:

for value in "${lesson[@]}"; do ...; done

Я бы также переименовать массива во множественном числе lessons.

Возвращаемое значение функции

Есть несколько тонких моментов, мне не нравится в этом коде:


function check_correct() {
if [ "$user_input" == "$string_to_type" ]; then
return;
else
echo "too many mistakes, try again!"
false;
fi
}

А return команды без параметра будут использовать код завершения последней выписки. В данном случае это успех. Мне было бы понятнее, если бы вы использовали явный return 0 есть.

В else ветвь заканчивается falseзаявление.
Если это последний оператор в функции,
затем код выхода из функции будет 1, как и предполагалось.
Но этого не достаточно явные.
Функция не возвращает сразу на falseзаявление.
Явный return 1 было бы гораздо лучше.

Как это:

function check_correct() {
if [ "$user_input" == "$string_to_type" ]; then
return 0
else
echo "too many mistakes, try again!"
return 1
fi
}

С другими моими предложениями дальше, я рекомендую писать эту функцию такой:

check_correct() {
if ! [ "$user_input" = "$string_to_type" ]; then
echo "too many mistakes, try again!" >&2
return 1
fi
}

Недокументированные возможности

В == оператор не задокументированы в man [.
По этой причине я рекомендую использовать = вместо == в [ ... ].

Стиль

Рекомендуемая функция декларация стиль без function ключевое слово:

start() {

Есть куча лишних точек с запятой в конце строк, которые могут быть безопасно удалены.

Вместо этого:


wpm=$((sec / time_it_took))

Вы можете написать немного проще, как это:

((wpm = sec / time_it_took))

Это тоже работает:

((wpm *= length_of_string / 5))

Я не помню объяснений, но вместо let count+=1, ((count+=1)) рекомендуется. Еще лучший способ, чтобы написать это ((count++)).

Заточка пилы


Я программирую немного лучше каждый год, но в этом году она практически не изменилась.

Просто продолжай делать это!

2
ответ дан 30 января 2018 в 10:01 Источник Поделиться

Я печатаю так быстро, что ваш сценарий должен был остановить с деление на ноль ошибка :Д


строка 64: [: скорость: ожидается выражение целого числа

Этот сегмент кода

count=0
while [ "$count" -ne "$length_of_string" ]; do
checkCharacter
done

не прозрачные, как count увеличивается. Я бы на месте (( count++ )) внутри цикла, а не в конце checkCharacter функция.

Я вижу, что ты пытаешься приложить осмысленные имена эти цифры, но вы оставили магическое число 5. Я знаю, что это среднее количество английских букв за слово, но число торчит как бельмо на глазу среди других имен переменных.

time_it_took=$SECONDS
sec=60
wpm=$((sec / time_it_took))
wpm=$((wpm * length_of_string / 5))

Мне тоже не нравится, как то же имя wpm присваиваются различные значения в последовательном порядке. Вы могли бы просто написано wpm=$(( sec / time_it_took * length_of_string / 5 )) или дали первое задание другое имя.

Все в всех, я бы написал его по-разному и с использованием меньшего количества функций.

1
ответ дан 31 января 2018 в 03:01 Источник Поделиться