diff --git a/.deepsource.toml b/.deepsource.toml
new file mode 100644
index 0000000..420b2aa
--- /dev/null
+++ b/.deepsource.toml
@@ -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"
\ No newline at end of file
diff --git a/README.md b/README.md
index a6c4033..c92504d 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
---
-
+
@@ -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`.
@@ -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:
@@ -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.
@@ -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 📜
@@ -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)
\ No newline at end of file
+[![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)
diff --git a/examples/Fill In The Blanks/main.py b/examples/Fill In The Blanks/main.py
new file mode 100644
index 0000000..969f9e3
--- /dev/null
+++ b/examples/Fill In The Blanks/main.py
@@ -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}'.")
\ No newline at end of file
diff --git a/examples/Word Jumble Game/main.py b/examples/Word Jumble Game/main.py
new file mode 100644
index 0000000..031111c
--- /dev/null
+++ b/examples/Word Jumble Game/main.py
@@ -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}'.")
diff --git a/lesp/autocorrect.py b/lesp/autocorrect.py
index 02190bb..915f6f3 100644
--- a/lesp/autocorrect.py
+++ b/lesp/autocorrect.py
@@ -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!")
@@ -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)
@@ -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)
\ No newline at end of file
+ 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)}")