Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/LyubomirT/lesp
Browse files Browse the repository at this point in the history
  • Loading branch information
LyubomirT committed Nov 29, 2023
2 parents 8a924d4 + 53d9293 commit d72b76f
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 21 deletions.
18 changes: 18 additions & 0 deletions .deepsource.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version = 1

exclude_patterns = [
"config",
"demo_config",
".gitignore",
"LICENSE",
"README.md",
"CONTRIBUTING.md",
"small_wordlist.txt",
"wordlist.txt"
]

[[analyzers]]
name = "python"

[analyzers.meta]
runtime_version = "3.x.x"
75 changes: 71 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
---

<div align="center">
<img src="https://img.shields.io/badge/Version-0.3.0-gold.svg" alt="version">
<img src="https://img.shields.io/badge/Version-0.3.5-gold.svg" alt="version">
<img src="https://img.shields.io/badge/License-BSD%203--Clause-blue.svg" alt="license">
<img src="https://img.shields.io/badge/Python-3.2+-green.svg" alt="python">
<img src="https://img.shields.io/badge/Platform-Linux%20%7C%20Windows%20%7C%20macOS-lightgrey.svg" alt="platform">
Expand Down Expand Up @@ -102,7 +102,7 @@ In the code above, we're getting similar words to `apgle` with a similarity rate

A similarity rate of `0.5` means that the words returned will be at least 50% similar to the word we're checking. The higher the similarity rate, the more precise the results will be, but generally there will be less words. Myself I would recommend to keep the similarity rate at `0.5`, but you can experiment with it and see what works best for you.

The `chunks` argument specifies how many chunks the wordlist will be split into. This is useful if you have a large wordlist and you want to speed up the process. The higher the number, the faster the process will be, but the more memory/CPU it will consume. For example, when trying to scan `wordlist.txt` with 500 chunks, the process takes about 0.5 seconds on my machine, but it consumes about 1.5 GB of RAM and 44% of one of the CPU cores. If you have a large wordlist.
The `chunks` argument specifies how many chunks the wordlist will be split into. This is useful if you have a large wordlist and you want to speed up the process. The higher the number, the faster the process will be, but the more memory/CPU it will consume. For example, when trying to scan `wordlist.txt` with 1500 chunks, the process takes about 0.5 seconds on my machine, but it consumes about 1.5 GB of RAM and 44% of one of the CPU cores. If you have a large wordlist.

The `upto` argument specifies how many similar words will be returned. If you set it to `3`, then the function will return up to 3 similar words. If you set it to `1`, then it will return up to 1 similar word. But, whatever amount you select, the output will still be a list. If you set it to `0`, then the function will raise a `ValueError`.

Expand Down Expand Up @@ -159,6 +159,16 @@ if not is_correct("reactjs") and get_similar("reactjs") is None:
pass
```

You can also extend the wordlist with multiple words at once by passing a list or a tuple to the function. Like this:

```python
from lesp import extend_wordlist

words = ["reactjs", "vuejs", "angularjs"]

extend_wordlist(words)
```

### Remove from wordlist

An opposite of the `extend_wordlist` function, this function removes a word from the wordlist. Note that this function will raise a `ValueError` if the word is not in the wordlist. Also note that this function will not remove the word from the wordlist permanently, it will only remove it for the current session. Here's an example:
Expand All @@ -170,6 +180,62 @@ word = "reactjs"
remove_from_wordlist(word)
```

If you want to remove multiple words at once, you can pass a list or a tuple to the function. Like this:

```python
from lesp import remove_from_wordlist

words = ["reactjs", "vuejs", "angularjs"]

remove_from_wordlist(words)
```

### Stacking

This function lets you stack two wordlist files together, so you can have a bigger wordlist out of two combined. The function will take two arguments, the source file and the destination file. The source file is the file that will be stacked on top of the destination file. Here's an example:

```python
from lesp import stack

stack("wordlist.txt", "my_wordlist.txt")
```

### Merge delete

This function lets you delete all words from the destination file that are in the source file. For example, if you have a wordlist with the following words:

```
apple
banana
orange
```

And you have another wordlist with the following words:

```
apple
banana
raspberry
```

Then, if you use the `merge_delete` function, the destination file will be modified to look like this:

```
orange
raspberry
```

Here's an example of how you can use it:

```python
from lesp import merge_delete

merge_delete("wordlist.txt", "my_wordlist.txt")

with open("my_wordlist.txt", "r") as f:
print(f.read())
```

## Examples 📝

If you're still not sure where to use LESP, you can check out the `examples` folder. It contains some examples of how you can use LESP in your projects. These examples are pretty simple, but they should give you an idea of how you can use LESP in your projects.
Expand Down Expand Up @@ -219,7 +285,6 @@ You can contact me on Discord either in my [Discord Server](https://discord.gg/X
- [ ] Optimize even further
- [ ] Add more examples
- [ ] Improve documentation
- [ ] Add support for compounds

## License 📜

Expand All @@ -236,4 +301,6 @@ Many thanks to the following Open-Source projects:

Thanks to these awesome people for contributing! I appreciate your support a lot! ❤️

![Contributors](https://contrib.rocks/image?repo=LyubomirT/lesp)
[![Contributors](https://contrib.rocks/image?repo=lyubomirt/lesp)](https://github.com/lyubomirt/lesp/graphs/contributors)

(Note that due to a glitch, some contributors may not appear in the grid)
27 changes: 27 additions & 0 deletions examples/Fill In The Blanks/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#from lesp import is_correct
from lesp.autocorrect import is_correct, get_similar
import random

# Load words from wordlist file
with open("wordlist.txt", "r") as f:
words = [word.strip() for word in f.readlines()]
random_word = random.choice(words)

# Create a word with blanks
word_with_blanks = ""
for i, letter in enumerate(random_word):
if i % 2 == 0:
word_with_blanks += letter
else:
word_with_blanks += "_"

print("Fill in the blanks:", word_with_blanks)

# User input
user_input = input("Your guess: ")

# Check spelling
if user_input.lower() == random_word:
print("Correct!")
else:
print(f"Incorrect. The correct word is '{random_word}'.")
21 changes: 21 additions & 0 deletions examples/Word Jumble Game/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#from lesp import is_correct
from lesp.autocorrect import is_correct, get_similar
import random

# Load words from wordlist file
with open("wordlist.txt", "r") as f:
words = [word.strip() for word in f.readlines()]

# Pick a random word and scramble it
word = random.choice(words)
scrambled = ''.join(random.sample(word, len(word)))
print("Unscramble this word:", scrambled)

# User guesses
guess = input("Your guess: ")

# Check if guess is correct
if guess.lower() == word:
print("Correct!")
else:
print(f"Incorrect. The correct word was '{word}'.")
127 changes: 110 additions & 17 deletions lesp/autocorrect.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ def load_wordlist():
try:
with open(wordlistpath, "r") as f:
wordlist = f.read().split("\n")
if not all(word.isalpha() for word in wordlist):
raise ValueError("Invalid wordlist format. Words must contain only alphabetic characters.")
return wordlist
except FileNotFoundError:
raise FileNotFoundError(f"{wordlistpath} not found!")
Expand All @@ -26,10 +28,7 @@ def load_wordlist():
exit()

def is_correct(word):
if word in wordlist:
return True
else:
return False
return word in wordlist

def get_similarity_score(word1, word2):
len1 = len(word1)
Expand Down Expand Up @@ -95,20 +94,114 @@ def backup(path="wordlist_backup"):


def restore(overwritecurrent, path="wordlist_backup"):
if not os.path.isfile(path):
raise FileNotFoundError("Backup file not found!")
with open(path, "r") as f:
wordlist_ = f.read().split("\n")
global wordlist
wordlist = wordlist_
if overwritecurrent:
with open(wordlistpath, "w") as f:
f.write("\n".join(wordlist))
try:
if not os.path.isfile(path):
raise FileNotFoundError("Backup file not found!")

with open(path, "r") as f:
wordlist_ = f.read().split("\n")

if not all(word.isalpha() for word in wordlist_):
raise ValueError("Invalid backup file format. Words must contain only alphabetic characters.")

global wordlist
wordlist = wordlist_

if overwritecurrent:
with open(wordlistpath, "w") as f:
f.write("\n".join(wordlist))
except Exception as e:
raise ValueError(f"Error during restore: {str(e)}")

def extend_wordlist(word):
wordlist.append(word)
if isinstance(word, str):
if word.isalpha():
wordlist.append(word.lower())
else:
raise ValueError(f"Invalid input: '{word}' is not a valid word.")
elif isinstance(word, (list, tuple)):
for w in word:
if isinstance(w, str) and w.isalpha():
wordlist.append(w.lower())
else:
raise ValueError(f"Invalid input: '{word}' is not a valid word.")
else:
raise TypeError("Invalid input type. Please provide a string, list, or tuple of alphabetic words.")

def remove_from_wordlist(word):
if word not in wordlist:
raise ValueError(f"\"{word}\" not in wordlist!")
wordlist.remove(word)
if isinstance(word, str):
if word.isalpha():
if word in wordlist:
wordlist.remove(word)
else:
raise ValueError(f"\"{word}\" not in wordlist!")
else:
raise ValueError(f"Invalid input: '{word}' is not a valid word.")
elif isinstance(word, (list, tuple)):
for w in word:
if isinstance(w, str) and w.isalpha():
if w in wordlist:
wordlist.remove(w)
else:
raise ValueError(f"\"{w}\" not in wordlist!")
else:
raise ValueError(f"Invalid input: '{word}' is not a valid word.")
else:
raise TypeError("Invalid input type. Please provide a string, list, or tuple of alphabetic words.")


def stack(source, destination):
try:
with open(source, "r") as f:
source_words = f.read().split("\n")
with open(destination, "r") as f:
destination_words = f.read().split("\n")

if any(len(word.split()) > 1 for word in source_words):
raise ValueError("Invalid source file format. Each word must be on a separate line.")
if any(len(word.split()) > 1 for word in destination_words):
raise ValueError("Invalid destination file format. Each word must be on a separate line.")

if not all(word.isalpha() for word in source_words):
raise ValueError("Invalid source file format. Words must contain only alphabetic characters.")
if not all(word.isalpha() for word in destination_words):
raise ValueError("Invalid destination file format. Words must contain only alphabetic characters.")

destination_words.extend(source_words)

with open(destination, "w") as f:
f.write("\n".join(destination_words))
except FileNotFoundError as e:
raise FileNotFoundError(f"File not found: {str(e)}")
except Exception as e:
raise ValueError(f"Error during stacking: {str(e)}")

def merge_delete(source, destination):
try:
with open(source, "r") as f:
source_words = f.read().split("\n")
with open(destination, "r") as f:
destination_words = f.read().split("\n")

if any(len(word.split()) > 1 for word in source_words):
raise ValueError("Invalid source file format. Each word must be on a separate line.")
if any(len(word.split()) > 1 for word in destination_words):
raise ValueError("Invalid destination file format. Each word must be on a separate line.")

if not all(word.isalpha() for word in source_words):
raise ValueError("Invalid source file format. Words must contain only alphabetic characters.")
if not all(word.isalpha() for word in destination_words):
raise ValueError("Invalid destination file format. Words must contain only alphabetic characters.")

destination_words_ = list(set(destination_words) - set(source_words))

# All other words in the source file that are not in the destination file will be added to the destination file

destination_words_ += [word for word in source_words if word not in destination_words]

with open(destination, "w") as f:
f.write("\n".join(destination_words_))
except FileNotFoundError as e:
raise FileNotFoundError(f"File not found: {str(e)}")
except Exception as e:
raise ValueError(f"Error during merge delete: {str(e)}")

0 comments on commit d72b76f

Please sign in to comment.