How to make keystroke auto completion in Python? - python

I am working on making a function which does auto completion based on keystrokes.
Like, in google.com when I hit 'a' in search bar, it shows the related search words such as amazon, amazon prime, airbnb...
I am trying make this function using Python and my CSV file based on detecting keystrokes.
There are some words in the CSV file such as Behavior, Building, Chemistry, History, Manufacturing, Mathematics.
The structure of my code consists of
while # infinitely looping in order to keep detecting keystrokes
for word in data
for char in range(numOfKeyStrokes)
The problem is, when I hit 'c', it is supposed to print out chemistry and it works great.
But when I hit 'h' after I already hit 'c', there is no response.
I want to make this printing out "chemistry" again.
I think when I hit 'h', the compiler doesn't go into "for word in data" statement but I don't know why.
There are some junk print outs in order to detect where the problem is.
Here is my code. Can someone help my problem?
import keyboard
import csv
import time
global numOfKeyStrokes #In order to compare each elemtn's letter one by one with keystroke
numOfKeyStrokes = 0
def keyStroke():
temp = keyboard.read_key()
time.sleep(0.1)
global numOfKeyStrokes
numOfKeyStrokes += 1
return temp
def init():
f = open('./DataBase.csv')
data = csv.reader(f)
getKeyStroke = []
matchingFlag = False
while True: # looping in order to keep getting keystrokes
global numOfKeyStrokes
getKeyStroke.append(keyStroke())
print(getKeyStroke)
print("numOfKeyStrokes ", numOfKeyStrokes)
for word in data: # each row is an each cell in a csv file
matchingFlag = False
for char in range(numOfKeyStrokes): # each x is an each letter in an each cell
print("word[9][char]==getKeyStroke[numOfKeyStrokes-1]", word[9] [char].lower(),",",getKeyStroke[numOfKeyStrokes-1])
if word[9][char].lower() == getKeyStroke[numOfKeyStrokes-1]:
print("char matched")
matchingFlag = True
break
else:
matchingFlag = False
break
if matchingFlag == True : print(word[9])
f.close()
init()

The reason your code only works one time is because you open the csv file once at the beginning of your init function.
When you pass it to the csv.reader and iterate over the entire file, you consume the resource. When you go for the next iteration the file/reader is empty and so your for word in data loop will not run.
I've refactored your program rather significantly, so I don't necessarily know if this still achieves your desired behaviour, especially without knowing exactly how your csv is setup, but I think you were looking for something like:
import csv
import time
import keyboard
def key_stroke_gen():
num_of_key_strokes = 0
while True:
num_of_key_strokes += 1
yield num_of_key_strokes, keyboard.read_key()
time.sleep(0.1)
def init():
get_key_stroke = []
words = []
with open('./DataBase.csv') as f:
data = csv.reader(f)
for row in data:
for word in row:
words.append(word.strip().lower())
for num_of_key_strokes, key_stroke in key_stroke_gen():
get_key_stroke.append(key_stroke)
for word in words:
if word[:num_of_key_strokes] == ''.join(get_key_stroke):
print(word)
if __name__ == '__main__':
init()
Generating the search_str directly in the generator might be a better approach overall, since it's easier to manage the building of the search string in one place and have the processing code separate.
import csv
import time
import keyboard
def search_strs():
search_str = ""
while True:
time.sleep(0.1)
key_press = keyboard.read_key()
if key_press == "backspace" and search_str:
search_str = search_str[:-1]
elif len(key_press) == 1 and ('a' <= key_press <= 'z'):
search_str += keyboard.read_key()
else:
continue
yield search_str
def init():
words = []
with open('./DataBase.csv') as f:
data = csv.reader(f)
for row in data:
for word in row:
words.append(word.strip().lower())
for search_str in search_strs():
for word in words:
if word[:len(search_str)] == search_str:
print(word)
if __name__ == '__main__':
init()

Related

Make a live updating counter to show the number of remaining characters WHILE the user inputs the text in CLI (windows + python)

Basically the headline.
In Python, I want to take max 280 characters of input from the user, and show a live updating counter on the CLI as the user types the input.(Similar to a Progress bar)
Getting some text to update on the screen is simple, but I don't know how to count the characters as the user is inputting them.
P.S. First-time StackOverflow user, please go easy on me. :)
EDIT:
Codebase: https://github.com/Prathamesh-Ghatole/100DaysOfCode-Writer/blob/master/main.py
I don't have a specific code snippet where I want to implement it yet.
But I basically want to take character input from the user in a loop where each iteration does the following:
Take single character input.
update a variable that counts the total number of input characters.
subtract the number of input characters from the character number limit.
Trigger a flag when the character limit is exceeded.
Using pynput package this seems to work.
from pynput.keyboard import Key, Listener
import os
length = 0
char_count = dict()
text = str()
def on_press(key):
try:
global text
global char_count
global length
if length >= 280:
print("[+] Character Limit Excided!")
return False
elif key == Key.enter:
return False
else:
os.system("cls")
if key == Key.space:
text += ' '
else:
text += f"{key.char}"
char_count[text[-1]] = char_count.get(text[-1], 0) + 1
length += 1
print(f"Enter Text: {text}")
print(f"Characters Left: {280 - length}")
print(f"Char Count {char_count}")
except:
exit()
def main():
os.system("cls")
with Listener(on_press=on_press) as listner:
print("Enter Text: ")
listner.join()
if __name__ == '__main__':
main()

How can store text and then search for it using Python

**I am making a program that takes a screenshot of a word, then translates that picture into text. I want to store that text somewhere. However, everytime get a new word to add, i want to check to see if that word is already present in the File/list/(whatever you think is the correct data storage). Now that the aim of the prgram is explained, I will detail the issue. The code doesn't recognise that new item added to the list is already in the list. It should print a 1 if present and a 2 if not, the code only ever prints a 2 **
import easyocr
import pyautogui
import time
import cv2
import numpy as np
reader = easyocr.Reader(['en'])
tag = 1
while True:
time.sleep(3)
image = pyautogui.screenshot(region=(670,400,550,130))
image = cv2.cvtColor(np.array(image),
cv2.COLOR_RGB2BGR)
tag+=1
img = cv2.imwrite(f"img/image{tag}.png", image)
file_name = f"img/image{tag}.png"
results = reader.readtext(file_name)
text=""
for result in results:
text += result[1] + " "
text = text.strip("")
"""my_list = [text]
for item in my_list:
if item == text:
print("1")
print("2")"""
file_object = open("wordlist.txt", "a")
text = text.strip(" ")
file_object.write(f'"{text}",')
file_object.close()
List = open("wordlist.txt").readlines()
My_List = [List]
print(List)
for item in List:
if item == text:
print("1")
print("2")
Does it not always print 2 because it's after the loop. I mean that when the loop is done it will print 2 even though it found the text or not. I usually make a boolean and if I found the text piece I make it true and else I make it false. Then I just check after the loop whether the boolean is true or false.
foundtext = False;
for item in List:
if item == text:
foundtext = True
if foundtext == True:
print(1)
else:
print(2)
But I don't know why it doesn't print 1.

Python create new line on space button press

I am running Python 3.8 (Also tested on 2.7). Attached below is code to a keylogger that I created with reference to a video tutorial as I'm fairly new to Python and trying to learn. I am trying to make it where when the space key is pressed, it writes a new line to the file so it tabs down and looks nicer. I've tried a few different things online that I've found however nothing has fixed it. If someone could help me and explain why this doesn't work it would be much appreciated. Thanks and have a great week
# Define imports
import pynput
from pynput.keyboard import Key, Listener
# Define variables for keylogger
count = 0
keys = []
# Function to detect key presses
def on_press(key):
global count, keys
keys.append(key)
count += 1
print(str(key))
if count >= 1:
write_file(str(keys))
keys = []
count = 0
# Function to write the letters to a file
def write_file(keys):
with open("log_test.txt", "a") as f:
for key in keys:
k = str(key).replace("'", "").replace("u", "").replace("]", "").replace(",", "").replace("[", "")
if k.find("space") >= 0: # This is the code to check for space bar press
f.write('\n')
else:
k.find("Key") == -1
f.write(k)
# Detect when a key is released
def on_release(key):
if key == Key.esc:
return False
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
That's because your "k" is not "space", but "s", "p", "a", "c", "e".
Not the most elegant method, but try this:
def on_press(key):
global count, keys
keys.append(key)
count += 1
if count >= 1:
write_file(keys) # don't convert to string here
keys = []
count = 0
def write_file(key):
with open("log_test.txt", "a") as f:
if str(key).find("space") >= 0: # transform to string to find what you want
f.write('\n')
elif str(key).find("Key") == -1: # transform to string to find what you want
# key will come as a list, like this: ['char']
# take the first (and only) element, and it will be like this: 'char'
# then remove the "'" and you'll have your character
key = str(key[0]).replace("'", '') # take only the character, then save it
f.write(key)
When you are checking for space, do this:
if k.find(" ") >= 0: # use plain space " " and not "space"
f.write('\n')

Python Spell Check With Suggestions

I have a program that I'm working on that takes an input and checks it to see if it spelled correctly with a dictionary inside of a file. However, I want to return a suggestion or two as well of what the person means. Any suggestions of how to do this? I have found some modules that can do it, but not for a specific dictionary from a file. Any help is appreciated!!
Here is what I have now:
def getDictionary():
theDictionary = open("theDictionary.txt", "r")
dictionaryList = []
for eachLine in theDictionary:
splitLines = eachLine.split()
dictionaryList.append(splitLines[0])
theDictionary.close()
return dictionaryList
def spellChecker(theFile, theDictionary):
lowerItems = theFile.lower()
wordList = lowerItems.split()
wrongList = []
for item in wordList:
if item not in theDictionary:
result = False
wrongList.append(item)
else:
result = True
wrongItem = ""
return (result, wrongList)
def main():
theDictionary = getDictionary()
theText = getFile()
theInput = input("Input some words here:")
result, wrongList=spellChecker(theInput,theDictionary)
if result:
print("There are no spelling errors in the sentence! Hooray!")
else:
if len(wrongList) == 1:
print('There is a spelling error in the sentence! The word that is wrong is "' + str(wrongList) + '".')
elif len(wrongList) > 1:
print('There are some spelling errors in the sentence! The words that are wrong are"' + str(wrongList) + '".')
main()
You might want to have a look at the difflib module in the Standard Library. It allows you to do approximate string matching, which seems to be what you want.
It really does not matter if your dictionary is inside a file or not, since you are loading it into a list anyway. Maybe have a look at the get_close_matches() method in the said module.

How to get rid of frame 'blinking' effect with standard libs?

I am currently playing with some cmd/prompt animations/graphics:
import os
import time
def printFrame(timeout, count):
os.system('cls')
l=0
while True:
for k in range(0,9):
for i in range(0,9):
for j in range(0,9):
if j == k and i != 4:
print("|", end="", flush=True)
elif j !=k and i == 4:
print("-", end="", flush=True)
elif j ==k and i == 4:
print("+", end="", flush=True)
else:
print("O", end="", flush=True)
print("")
time.sleep(timeout)
os.system('cls')
l += 1
if l > count:
break
if __name__ == "__main__":
printFrame(0.08, 2)
and i want to get rid of frame blinking - especialy visible in first line, my idea was to use second printing thread:
def printFrame(timeout, count):
#print from example1
def printFrameTwo(timeout, count):
#print from example1 without os.system('cls')
if __name__ == "__main__":
p1 = threading.Thread(target = printFrame, args = (0.08, 2))
p2 = threading.Thread(target = printFrameTwo, args = (0.08, 2))
p1.start()
p2.start()
but the effect was rather disappointing - problems with synchronization and first line still very blinky, second idea was to use 'predefined frames' - but its not very educating - the bonus here is that I can print whole line at once, but still effect is not as expected, third (most promising) idea is to only change necessary 'pixels'/chars in frame - but here I need to move in frame between lines! and curses is not working on windows (at least not in standard). Do you maybe have some ideas how to bite it? (windows, standard libraries) maybe how to speed up 'os.system('cls')'?
I figured it out... You can use ANSI codes to move the cursor then clear the lines without any BLINK!
print('\033[4A\033[2K', end='')
\033[4A Moves the cursor 4 lines up (\033[{lines}A you can replace lines with however many you need) \033[2K Clears all those lines without the screen blinking. You can use it in a simple typewrite function that needs a constant message or a box around it like this:
from time import sleep
def typewrite(text: str):
lines = text.split('\n')
for line in lines:
display = ''
for char in line:
display += char
print(f'╭─ SOME MESSAGE OR SOMEONES NAME ────────────────────────────────────────────╮')
print(f'│ {display:74} │') # :74 is the same as ' ' * 74
print(f'╰────────────────────────────────────────────────────────────────────────────╯')
sleep(0.05)
print('\033[3A\033[2K', end='')
The only problem with this is that the top line is blinking. To fix this all we need to do is to add a empty line that is blinking so the user cant see it. We also move the cursor up from 3 to 4 lines.
def typewrite(text: str):
lines = text.split('\n')
for line in lines:
display = ''
for char in line:
display += char
print('')
print(f'╭─ SOME MESSAGE OR SOMEONES NAME ────────────────────────────────────────────╮')
print(f'│ {display:74} │') # :74 is the same as ' ' * 74
print(f'╰────────────────────────────────────────────────────────────────────────────╯')
sleep(0.05)
print('\033[4A\033[2K', end='')
To make this into your code just print your text and add a print('') at the start. Then use this print('\033[4A\033[2K', end='') but change the 4 to however many lines that you printed including the print(''). Then it should work without blinking. You can put print('\033[4B', end='') at the end which just moves the cursor back up.
If you want to hide the cursor you can use this gibberish or make the cursor the same color as the background:
import ctypes
if os.name == 'nt':
class _CursorInfo(ctypes.Structure):
_fields_ = [("size", ctypes.c_int),
("visible", ctypes.c_byte)]
def hide_cursor() -> None:
if os.name == 'nt':
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
ci.visible = False
ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
def show_cursor() -> None:
if os.name == 'nt':
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
ci.visible = True
ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
Note: All of this is still new to me so I am still testing this out to fully understand it.

Categories