在這個易於理解的教程中,您將學習如何在幾分鐘內建立自己的 MonkeyType CLI 版本。 😎
您將學到什麼:✨
您準備好成為 CLI MonkeyTyper 了嗎? 😉 無論這是您的第一個 CLI 應用程式還是第 n 個應用程式。請隨意跟隨。
ℹ️不需要設定虛擬環境,我們不會使用任何外部相依性。
建立一個資料夾來保存專案的所有原始程式碼:
mkdir cli-monkeytype-python
cd cli-monkeytype-python
建立兩個新文件,我們將在其中編寫程式:
touch main.py typing_test.py
main.py
檔案將作為我們應用程式的起點,而typing_test.py
檔案將保存程式的所有邏輯。
ℹ️對於Linux或Mac用戶,您不需要下載任何依賴項,我們將主要使用curses 、 time和random模組,這些模組都包含在Python標準庫中。
⚠️注意
Windows 使用者可能必須安裝curses,因為它不包含在Windows 的Python 標準庫中。在繼續下一步之前,請確保已安裝它。
💡 我們將在本節中研究應用程式的方法、大綱和實際編碼部分。 😵💫
我們將在這裡採取不同的方法,而不是將所有程式碼都塞在main
文件中。我們將把程式碼分成不同文件中的類別。
將有一個單獨的文件,其中包含一個負責封裝與打字測試相關的所有邏輯的類別。在主文件中,我們將呼叫此類的方法。聽起來,對吧?讓我們開始吧。 🚀
這是我們類別的骨架以及我們將要處理的所有方法。
class TypingTest:
def __init__(self, stdscr):
pass
def get_line_to_type(self):
pass
def display_wpm(self):
pass
def display_accuracy(self):
pass
def display_typed_chars(self):
pass
def display_details(self):
pass
def test_accuracy(self):
pass
def test_wpm(self):
pass
所有函數名稱都應該是不言自明的。如果您需要協助理解每個函數的作用,即使在查看了此大綱之後,為什麼還要閱讀這篇文章?只是開玩笑*不是真的*。 😏
🥱 這是一個適合初學者的應用程式。別擔心,一起編碼吧。
我們將從導入模組並編寫__init__
方法開始。這將初始化程式執行所需的所有術語。
import curses
import random
import time
class TypingTest:
def __init__(self, stdscr):
self.stdscr = stdscr
self.to_type_text = self.get_line_to_type()
self.user_typed_text = []
self.wpm = 0
self.start_time = time.time()
# Initialize color pairs
curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK)
# --SNIP--
stdscr
用於控制終端螢幕,對於建立使用者可以看到其擊鍵的基於文字的使用者介面至關重要。 ⌨️
get_line_to_type
方法取得一行文字供使用者鍵入。該文字儲存在self.to_type_text
變數中。當他們鍵入時,他們輸入的字元將保存在self.user_typed_text
清單中。我們使用列表是因為當使用者更正錯誤輸入的字元時,彈出最後一項會更容易。
初始每分鐘字數 (WPM) 分數設定為 0,我們記錄測驗的開始時間。我們也初始化了一些顏色對,根據它們是否正確來指示字元上的顏色。稍後,我們將根據使用者打字所需的時間來計算WPM 。
現在,新增以下功能的程式碼
ℹ️ 確保在專案根目錄中建立一個名為
typing_texts.txt
的新文件,其中包含幾行文字。參考:點這裡。
# --SNIP--
def get_line_to_type(self):
with open("typing_texts.txt", "r", encoding="utf-8") as file:
lines = file.readlines()
return random.choice(lines).strip()
def display_wpm(self):
self.stdscr.addstr(1, 0, f"WPM: {self.wpm}", curses.color_pair(3))
def display_accuracy(self):
self.stdscr.addstr(
2,
0,
f"Accuracy: {self.test_accuracy()}%",
curses.color_pair(3),
)
def display_typed_chars(self):
for i, char in enumerate(self.user_typed_text):
correct_character = self.to_type_text[i]
# Use color pair 1 if correct, else color pair 2.
color = 1 if char == correct_character else 2
self.stdscr.addstr(0, i, char, curses.color_pair(color))
def display_details(self):
self.stdscr.addstr(self.to_type_text)
self.display_wpm()
self.display_accuracy()
self.display_typed_chars()
# --SNIP--
讓我總結一下這些方法,它們非常簡單:
🎯 get_line_to_type(self)
:從名為「typing_texts.txt」的檔案中擷取刪除了尾隨空格的隨機行。
🎯 display_wpm(self)
:當使用者鍵入時在螢幕上的第一行顯示 WPM。
🎯 display_accuracy(self)
:在螢幕上第 2 行顯示準確率百分比。準確率由我們即將編寫的test_accuracy()
方法計算。
🎯 display_typed_chars(self)
:顯示使用者在螢幕上輸入的字符,突出顯示一個顏色對(顏色 1)中的正確字符和另一個顏色對(顏色 2)中的錯誤字符。
🎯 display_details(self)
:它本質上是一個輔助函數,幫助顯示上面所有顯示函數的內容。
好的,現在我們已經編寫了這些顯示方法,讓我們實現實際的邏輯來測試準確性和 WPM 本身。
新增以下程式碼行:
# --SNIP--
def test_accuracy(self):
total_characters = min(len(self.user_typed_text), len(self.to_type_text))
# If there are no typed chars, show accuracy 0.
if total_characters == 0:
return 0.0
matching_characters = 0
for current_char, target_char in zip(self.user_typed_text, self.to_type_text):
if current_char == target_char:
matching_characters += 1
matching_percentage = (matching_characters / total_characters) * 100
return matching_percentage
def test_wpm(self):
# getkey method by default is blocking.
# We do not want to wait until the user types each char to check WPM.
# Else the entire logic will be faulty.
self.stdscr.nodelay(True)
while True:
# Since we have nodelay = True, if not using max(),
# users might end up with time.time() equal to start_time,
# resulting in 0 and potentially causing a zero-divisible error in the below line.
time_elapsed = max(time.time() - self.start_time, 1)
# Considering the average word length in English is 5 characters
self.wpm = round((len(self.user_typed_text) / (time_elapsed / 60)) / 5)
self.stdscr.clear()
self.display_details()
self.stdscr.refresh()
# Exit the loop when the user types in the total length of the text.
if len(self.user_typed_text) == len(self.to_type_text):
self.stdscr.nodelay(False)
break
# We have `nodelay = True`, so we don't want to wait for the keystroke.
# If we do not get a key, it will throw an exception
# in the below lines when accessing the key.
try:
key = self.stdscr.getkey()
except Exception:
continue
# Check if the key is a single character before using ord()
if isinstance(key, str) and len(key) == 1:
if ord(key) == 27: # ASCII value for ESC
break
# If the user has not typed anything reset to the current time
if not self.user_typed_text:
self.start_time = time.time()
if key in ("KEY_BACKSPACE", "\b", "\x7f"):
if len(self.user_typed_text) > 0:
self.user_typed_text.pop()
elif len(self.user_typed_text) < len(self.to_type_text):
self.user_typed_text.append(key)
🎯 test_accuracy(self)
:透過將使用者輸入的字元與目標文字進行比較,計算並返回打字準確度(以百分比形式)。如果字元匹配,則將匹配字元的計數加1。最後,計算匹配的百分比。
🎯 test_wpm(self)
:計算每分鐘字數(WPM)並即時更新顯示。我們用一個公式來計算WPM,這不是我想出來的,我從網路複製的。它追蹤使用者輸入的內容,處理退格鍵,並在使用者完成輸入目標文字或按ESC時停止。
偉大的!這就是我們的TypingTest類別。 🎉
✅ 我們編寫程式碼的方式可以幫助我們輕鬆地將程式碼匯入到任何未來的專案中,並使維護變得更加容易。
是時候測試我們的實作了。 🙈
在main.py
檔案中,加入以下程式碼行:
from curses import wrapper
from typing_test import TypingTest
def main(stdscr):
stdscr.clear()
stdscr.addstr("Welcome to the typing speed test")
stdscr.addstr("\nPress any key to continue!")
while True:
typing_test = TypingTest(stdscr)
stdscr.getkey()
typing_test.test_wpm()
stdscr.addstr(
3,
0,
"Congratulations! You have completed the test! Press any key to continue...",
)
stdscr.nodelay(False)
key = stdscr.getkey()
# Check if the key is a single character before using ord()
if isinstance(key, str) and len(key) == 1:
if ord(key) == 27: # ASCII value for ESC
break
if __name__ == "__main__":
wrapper(main)
💡 注意:我們從curses
wrapper
方法內的main 函數,該函數處理curses 模組的初始化和清理。
在 main 中,我們建立TypingTest類別的實例並在無限循環中執行測試,這讓使用者可以繼續執行測試,直到他們決定按ESC退出。
讓我們看看它的實際效果。 🔥
🫵 如果你已經做到了這一步,我想指派一個小任務給你。目前,我們正在從文件中隨機選擇文字進行輸入。我希望您從網路上抓取輸入文字並使用該內容。請隨意在我的儲存庫中開啟包含您的變更的拉取請求。
如果您需要幫助,我已經參與了一個類似的 Python 抓取專案。請隨意檢查一下。
到目前為止,您已經建立了一個 Python CLI 應用程式來測試您在終端機中的打字速度。
本文的記錄原始碼可在此處取得:
https://github.com/shricodev/blogs/tree/main/cli-monkeytype-python
非常感謝您的閱讀! 🎉🫡
在下面的評論部分寫下你的想法。 👇
{% cta https://twitter.com/shricodev
%} 在 Twitter 上追蹤我 🐥 {% endcta %}
{% 嵌入 https://dev.to/shricodev %}
原文出處:https://dev.to/shricodev/build-your-own-cli-version-of-monkeytype-bm7