From 42646f17bef4cc1cd94516b962eef6037b3232a2 Mon Sep 17 00:00:00 2001 From: LyubomirT Date: Sun, 26 Nov 2023 17:21:31 +0200 Subject: [PATCH] Update README.md with project details and usage instructions. Add examples for development, and add a banner and a logo. --- README.md | 184 ++++++++++++++++++- branding/BANNER.png | Bin 0 -> 17932 bytes branding/LESP.png | Bin 0 -> 12786 bytes demo.py | 2 +- examples/A Simple Spell Checker/main.py | 19 ++ examples/A Word Game/main.py | 31 ++++ examples/Similarity Score Calculator/main.py | 49 +++++ {ac => lesp}/__init__.py | 0 {ac => lesp}/autocorrect.py | 5 + 9 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 branding/BANNER.png create mode 100644 branding/LESP.png create mode 100644 examples/A Simple Spell Checker/main.py create mode 100644 examples/A Word Game/main.py create mode 100644 examples/Similarity Score Calculator/main.py rename {ac => lesp}/__init__.py (100%) rename {ac => lesp}/autocorrect.py (90%) diff --git a/README.md b/README.md index 0c7bc7c..2f3fc3f 100644 --- a/README.md +++ b/README.md @@ -1 +1,183 @@ -# lesp-oneword \ No newline at end of file +
+

LESP - Lightweight Efficient Spelling Proofreader

+ +
+ +--- + +
+version +license +python +platform + +dependencies +
+ +## Welcome to the LESP repository! 👋 + +LESP is a lightweight, efficient spelling proofreader written in Python. It's designed to be easy to use and lightweight, while still providing a decent result when checking for spelling errors. Resource consumption is kept to a minimum, and the program is designed to be as fast as possible. + +## Features ✨ + +- Lightweight and efficient +- Easy to use +- Fast +- Cross-platform +- No dependencies +- (Kind of) Customizable + +## Installation 📥 + +Simply clone the repository and run the `demo.py` file to check it out. You don't need to install any additional libraries, so this is like plug-and-play. Just note that anything below Python 3.2 won't run this since old versions don't support `concurrent.futures`, which is used to speed up the process. + +### Detailed installation instructions + +1. Clone the repository + +```bash +git clone https://github.com/LyubomirT/lesp.git +``` + +2. Open the folder + +```bash +cd lesp +``` + +3. Run the demo + +```bash +python demo.py +``` + +## Usage 📖 + +LESP is pretty easy to setup, and basic configuration are already pre-built. You can find them in `config` and `demo_config` (these are files, not folders!) and you can edit them to your liking. Note that these files are **required** for the program to run, so don't delete, move, or rename them. + +### Basic usage + +To use LESP, you need to import `is_correct` and `get_similar` from the `lesp` module. Then, you can use them like this: + +```python +from lesp import is_correct, get_similar + +clearlynotcorrect = is_correct("apgle") # False + +if not clearlynotcorrect: + print("Did you mean: " + get_similar("apgle")) # Did you mean: apple +``` + +Simple as that! + +### Advanced usage + +You can use a different wordlist by specifying it in the `config` file. Just note that the wordlist must be a `.txt` file, and it must be in the same folder as the file you want to run. + +A wordlist must be structured with each word on a new line, like this: + +``` +apple +banana +orange +``` + +After you've done with putting a good wordlist in the directory, specify it in the `config` file like this: + +``` +wordlist="my_wordlist.txt" +``` + +You can customize the process of getting similar words as well. Configuration will be provided as arguments to the `get_similar` function. Here's an example: + +```python +from lesp import get_similar + +similar_words = get_similar("apgle", similarity_rate=0.5, chunks=4, upto=3) + +print(similar_words) +``` + +In the code above, we're getting similar words to `apgle` with a similarity rate of 0.5, splitting the wordlist into 4 chunks, and returning up to 3 similar words. + +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 `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`. + +### Get similarity score + +Even if this function isn't really supposed to be a feature, you can still use it if you want to. It's pretty simple to use, just import `get_similarity_score` from the `lesp` module and use it like this: + +```python +from lesp import get_similarity_score + +score = get_similarity_score("apple", "apgle") # 0.8 + +print(score) +``` + +The function will return a float between 0 and 1, where 0 means that the words are completely different, and 1 means that the words are exactly the same. + +## 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. + +## Contributing 🤝 + +Contributions, issues and feature requests are welcome! Feel free to check out the [issues page](https://github.com/LyubomirT/lesp/issues). + +### How to contribute? + +Thank you for your interest in contributing to LESP! Here's a quick guide on how to contribute: + +1. Fork the repository + +```bash +git clone https://github.com/LyubomirT/lesp.git +``` + +2. Make your changes + +3. Test your changes to make sure everything works as expected + +4. Commit your changes + +```bash +git commit -m "Your changes" +``` + +5. Push your changes + +```bash +git push +``` + +6. Open a pull request + +7. Wait for your pull request to be reviewed + +Once again, thank you for your support! + +## Reach out to the developer 👨‍💻 + +You can contact me on Discord either in my [Discord Server](https://discord.gg/XkjPDcSfNz) or in my DMs (@lyubomirt). Creating a discussion might also work, but I'm a bit faster to respond on Discord. + +## Future plans 📅 + +- [ ] Optimize even further +- [ ] Add more examples +- [ ] Improve documentation +- [ ] Add support for compounds + +## License 📜 + +This project is licensed under the BSD 3-Clause License. For more information, please refer to the `LICENSE` file. + +## Acknowledgements 🙏 + +Many thanks to the following Open-Source projects: + +- [Google 10000 English](https://github.com/first20hours/google-10000-english) - `small_wordlist.txt` +- [English Word List](https://github.com/dwyl/english-words) - `wordlist.txt` diff --git a/branding/BANNER.png b/branding/BANNER.png new file mode 100644 index 0000000000000000000000000000000000000000..f0637e3f6f4dddffdaea743a584ff880aabf5f79 GIT binary patch literal 17932 zcmeHvXH-*5zxM`26tJKu2vQUTrG?&$3epu(ARxU<3B9-AQ3Qp6qJR`ZK&1CxgVL0$ zw9r8!HG~eK=bd=YbMABRx*y*4-Y@T3_hhZC$=;cnJ@aq#`sF|oC2s)*v zs`LPYD8Wba;1kC|)3h;=3K}x^2P(Irg6_);;NqD3Z8e<};1zJfDhynobWt^MhoIBV zq&Ha%?`dYx$JI_p-$VbdrnIFqLcrY0*}_`D2jK#GLy)Y3kBhmbgS7{{g|)4nlN|R- zEt;F%&Pt9OE_PS&u8X4eV>?wpH|vLf_jD}%94w`*xE187WqqW<1PE&nb9Ntuqm#R| zj~w^!d8NT;(rp+w=;UT)BmF>0`L8bEN{;)nhlh(a4Cd|aE#NI8;Ou4#6OxjWf(Z)4 zgoXJ*4}N!FCl7NUekXShFatIF?>UsL-7VehTs-WYo!Cipnp-$~ddP8eQ?vgy^(_w% zH#>{JXLoWJF#mnWlQcvCY#L^6+g#{uN>`u zKgq@1&D~nZ*Tq_n`+>E)v!|P-_3s%-gZ`RC(aqZ2!`ez-SWsAmUr2~wSX>tNU%nze z<39%6@$pczl9#j)6BL#dwc)q4mbB&<6%@DTx3IDh;`6PCJK4%{`|w*?+n9SgdT`6@I{hAI#cpNoZfEPn&d)CN-)!u! zxnyDg_L%>{wp{*AxJlyoTgOO(2fhG%68URS;7asGvNq&>meib5PC$+!cL1#&=nN7y|2Za(1p`(1Uw%YpXiGql zzHU5UivhzDs(wzhWy#>7kpG}nXR_EO5h^armEng%^~khL%r0(n*C=3##hbRO9D*9} zu|vm#>EcHWQR!`GT3+*Rw@ERqgqI4uLk*XH+FKv#*^AYn1O&dRbOItXd(36SB4?gC#|FDo6>WvzS=lFjh+?t|-G+V2J0nmwerwskBlYAz4N zt7~?@O_w%)(X#6ouvc$-$x~$GiruN*`|s`FueA3fJa=t#=x1I$2-rcSuz6~beLYFW z4s8ziJBme42JjU$?CM``a3p3Wifl)VbSi1Y++IXyH7a?{CwdRF-8e%&mm};=o!^{A zm98rlbA%aYHyEB=S2vFFad=wyz&e<_8uii@+EW9-)^_Ua1*+);LxHed6OSOxA7M)n^dopXf2W#UYGvhxce5W1m8CgVPZtR5+S9C$e5qYu7-^{lcIAIm(Km%ycW`IdkhM^0@%z?|5D9p<1Rz<1{%lnc@m<%K@4xH zUdw})ycx_Y^a?IwYvPP07j2eQ`{W`h-eu73pVm5)Dz*#1&iOiFoGMuUETDjLbQl&U zeG%q^)peb!i`TAvE+SfB9IQxaNX_j+*^15ID;jVdrK8&#d3RKRzbRwac^hg?1e+Qx zCa!9Ztv6v>tb62T7eD=){BA?W+Vfq7a%vUj0LFdSpfn3im3kJtbefVRnODJ*#arC2 zBom(VVx=a%?$CF9GQ0fTyvxIYt&jR9*8h}g{a^&2SjXbRyNO9f%Be3t;E75+5ZOEf z7|&O|T2qRRQ3z68Qpl@a5xl0D;F`(>ee9aP&5`r)=tiCKLpdGjQx{*a^2Lzo)kV$t zo0P#pYlWH^3;m{BcDVNod z(Lg;((AnT1AXG)XF+43k3sFW481(wIwnWI4Yr$A)nj(S5bfJPLt5vwIsB2v03uoR0 zL*HTKHzBY0igP`!3Oi`$m*7KW&5h>oeozzwdM8d9oGw^^X{t&bdx-jY_H{;LVWqx% z(Ecq-cIXgL(+pm{H%l|E3rO;orv*I7T5%_6G%wSVxom+V|&?8erggj5t6rur})lEFOCzT#i& zW5-0AcnX>jOMAk<4Yy|{eo=n@3W{_e;(#urMi@iCV4dtI2SvzWvp1m5tBd6}{SK%s zn5d;|D&1Cya=$~@kh_cU=_Cn}B4cKXKS}$_Fiv4kH2|kIN#F9oy#KEGdBtq#GFG55 z8*<@n-A!QhuGfW5SJJqo4@R_v*ofMr^o<@1PWvr|Gz5Vu|0=NHrmp zC?l|z)eEBnQHjXaktZy1)Hk8MJJ5-n0>-@MX@Az|pj^x0BlJ+@9|Db;&NZPz5S1>OWVttP)s-|XjYbeUOal)dlRTQX%wLUS zv1T-NZmX`%WCbGEEut8u9&4kW=%9osU@d>RrEk=r0FN3m;;`L%bp^VEH%&>YXxrB_^6g$WlptoYCSuz7&X#TIG*ZXt3#Khk(S=1gE zJNfn3JHV!zXq|rva+^%R?vtItl!hDBJlDKFnm<#wlsozL6?r4!a2v4}a%S9n7S?~^ z@~EZz+~^0SIc*$_qv=9Dt$w&wo;o2- zaB$yJWyZplYaD7Ik{GevhE6m_RuI2x2DJ4kz|>==fneIHKmUHx=kk|i)KZn&&5{gP z8tp>l=*eH+FcYi1nys> zv;~4%tJkJiYW@1VKBRd0LRnO+^RyMrtIMY$?+#9Ox~He2J%OS4y*Ngy?$Ps;dwo5T zR*csyX?xC2^xQfwXKUZqMV`b_PIkQMjel$51H?P84#r@*r-uRBWGDVy8(lQ#3(V0k zl=gd`D6pwv!G?)QPs$IFi`8){@n24bkR#ux*BOV%af|A+G2b2#O?POsfGOk#5?jO} zORO!3;Lws0T(l8{nzCFj%|YK8gVWP#R?P++o+g~Is_V`d0t7e-=oe8BI-czzhQcFj zE-l?hwTSi#CELL%r{-x(+#Kv_ZFA+$gVXBMww}d`)I-<#AxEvzek#$9^(s#a*2k29 zLS*xA)^bv)f(2S0TrnZc+Fl~S+KwL%M!IjAK7(A|9yh2KYv(DyE%c(@>PGwdj4Vwr z;#(QELW4|qU*9x(fKgPgJt|FZh1GA58&;%?oi-yj)wt3?D6$j3(Y9G${c3Gg+fkE9 zy3_HeqEp9QlDMH4XQ9Ym_NJf7++=EL7rxwmnPDg50;9{{U6mPu794?dO0WW$=j$X<0P|B+jPimfOG-bj z6OUw7V1ymM&U9uRDgV;o_Llo4g+mj&Zf3g>v48p#j@F)Q3IT_6(aqQwUnsc;R-o;u zt0FL2SRse;LYH?h9=erR%~rQ7xqi^~``3A6nXS*$>=3jbUvuQvdR(f{LBUF~ooKSt zigi8Yg+-Rd-x+a4g})Q;1$a3DCEBYzy3r+?fGXHZFc3{#Xg{2>?oyr;HxNPD5X5<- zFixd)lQyGR^XyYaG^?M}{immX$WizoYUgUkR?tEWRP>O^+SrDLAF9pzE2W)TCZnjkmM=YUNTlY zep4c6+~WI%U@R-dL{a2T!@bWugxW6`>gIW9h*Un4L$m7i;5s!}{~6NyXTBE?`|R-w zFnNkFrj5&=45MzG;7=M0=&Z)~QtoV`NHl! z+@-S+<*FCIltKP|SMK2v`|;nJ%gEg0-xSj-GlDvP5Q}M*{iRJdR6CL#6h)RrzUr|h ze*A+#qpdnPUP&g1ktT=eRd_3kOrMPa-9N&VhMYglhw?5_td@~_Zuo!l_{)++gxEIB zo*O{c4g{ZX9C-)#wZ41OtnlKV5!p~)=4)wUW=1Ad^oe{`^V$*m#LX1a+|}_E=UoqT z1y})LUf)92vk>Aga-yAeYcu!GcFTI9mZ=jCWcpn$1@HtZ9aynNXq z{uq|^Y*cRhN9soN--0wxPTQzzyx&WsGJZ@M(RgyID)emA61n4-@bXqUc2;=34ive+ zGI8%;2bQ4lL;qaY1=JkaM8pWNtCuaf;>3G@;vGZvMNfXU%ia|IlVhYckq`!l`@yxg zwEOFoS>sNxOr4p-7w*>%B}bZ9Xi-i*5_=Pz6r0=%<0VvC3T}lzWMdfF6Qrd zD7fd3&djma?7z^KUVo>kX5xtE|DkQ>1RmPHhruVn0hIk2KBiAQ6;{Ie^S9^LepriZewpEVo}Gg z4-(Wcd}2^6%NjG$t@v{1z@wf41||)hCt zJ<^hE;-9{8U9BSv;IL9*vSOGTxyMLxpK?ld{HVcydYdpVvS>rw|DmARUQ2}R4A--i zF~i^fa70`1WoU_qVbY~y8C`bi7biQ`luU9=pb`5prghbdqCJpT4q&%gZx{Ot=~o!a z;JR~wpB@Yf*fDL1CqfqIUj4*tP);q2X1%J;q;5n+!iRFd4If4Eo`8Ho>dGwZWyWoz zbxksM#PLheaxef}SM+AGp|SVJ2Pmt06(Py2$dT)m8KaXe*-TWJLVOqFUQ$m-GbVtm)#$Jve)n znNWTr30tB}TV>d_b*=P?2pbMm*%i^wr=PpXWoy)K0*e-mC)r}1Ib&a!{<~(KOUpaX zK4fO8@0xMQ?ds9d>*0^ZAKfzNy=+8H4No4Oa;?X^au_oU2p~!qumyr{Gu0XUn@(@v z1oNHFqA60l37Po=iJ|S`&N`lMp z4TA;jG-yk>I@0FE`DVmXH;w=|2B67cJV_-*sd`daJkK*Ks+H89Z#2J09?hLd`KHu% zS5dL{vnLtrPsU&_GO}O1^8b8}nq83{TEdBg_qp=R7-NEa*oE`RO;@Ti{$O5+_xG|JvgA+2f$s6MWCI?)bBus@r4F1AguZ2{UKwzo)TieCs+k4O}ZmdL_ z2vjW=Xl4OeL5p8MfC&c%?>p6A2;ShvQP`_BYymSETmz{vQk{h=6oJ>^!bw*e%B3<+ z-TK`r<(O5TE!jkBg&~=~Ou6KT*k6X$X=T=IM=iJXASN)vk0kBa)nhC;L&jM)i=G$< z8JvLjox$`pJdl=F$(CgB(5%IR z;mQF6^vF&?^&sghNZ(RIoGEIsisJ?hSwQ2xNN3p|ILjKlr$!ke#Ve4NBH&9nAB!i= zdS+eMOG_|~a|d-J**$V$yK`ru`FLkbi1to)UH!|;UQx#KRAB;*6h(OI#)n{GaL@4g zU@G8qycKAKzKf73tIdaBe;aytY1skz_(#0X5|C^vIMH=0vLMI7z9%7LZ)zZln>{3c z-btNDO656Y;E)Y@V-T;FBMi#x8sMlqm1&(z-5B=Slj8R_HW0MIsjAeqvNPt2wTC0$ zDXWMTqm+^w9QGSeaXAULhPsfl65rr)cPD^_fA1QKcm)*^)d%oVQjbLFzS<4jpL-Ps zC=I~S2RQjn=($BD+_$)Re1dX_G5D}@97J@k&T1u`_~oI)<-b5K`;NMCT}ep&f~hU^ zf#E3XWaE9#qo^ijFW*L=dN}k~EdY5IxeF8>X5s74CS6V0vkpoIWg&0#ge9GtNGwQ~^AHe+yr&uJvOea*`ro;|?ry&up_ziisY}Wgc zTjs3-S`e_BtzKC^e$Meg@DU({|k*~4I zhV|%!D$D(heU?$!_{v03S4HBIziSX~qe5~r%%&cJ)F33HJZ3!Mahb*)rQI{A0f66` zK=^>|3o`{IW4caL=#!}+Lm_xsO{rLaNc+l{dvC=>bggN195j14qi_35RxvRZ_>MIM zanczgD$6Ep_J{3j_t85(qW1OPa`n^Ib1l{qEUfB}2a6G-4F?nC&{GoD{rT-`!YPX6 z&-XA)m4b%VT~B2c_O_}v(oNYsMIh+-7sg-+y#7C{lF+y7KLu8$A6pi4-D+WegbeZ} z#Y*{&Kp09J%k(rbk5^m4N?YHLv0x>cMD?M^`f zM{`z7p!LvOR(z4m^W6j-#TTxcXlG>y5)k1Y3*s834fr|D?xw1gCKJvOPOeWK+V5|) zHEUi=*s_s57|1+cQb;k^rDUB(-=Z#bPhOmjhWn!Bid3IAA48hXjaCkVe7R+}ZL!hg z_mvB7I-lBKXBY%vJG3Hd3@jJMGzcwc4%!T_UcHL2T5~qpD4?r60j=Kx2d<&dgtyTp zs>p67rRMrdg>%mS8&uMrc^M3XjB}-R-YlTT-Ze=q#`k4iKdi5mVeKN4> z;sY>Vfd#fxkZUp9Xa(qI5PK)~4rtN)$OeU@AI^0i3%mLTM_V$i;b3-$%s|%eUzeTQ zXeNAgjduS?C&hUx& z8)vpkcX=CdlXcg(FWc8=vIXEK+rG8UVh5c4Y?R6--VhGj^A)91>T8a48QQM($V%iq z%>Pg*Z5+9%BSm7~^=mA+0)mtJ)KrHzvrGdteQTo%7OU!TD&x}4HyNQ%taxB zQoiNrt@sH;lwz9=U}$coTpb?&=63F4d1fF!acCPy$hrRrPn96vcil_2yL&$2@-uhX zFas$XtcAPyaunUVe?=|Yvk?DnSlyKH@cOmlxhbo+xgh2e3&Il->q<9xG!&4;&;Ale zd2azRZUR5ij7CibsuF*kg-LMjv1N;FwGd%F9C>j)mPW|`v2a3{BEo5oyGf9 znTPja6HQ08^+&cT%%!$kD%Fo7w2po(;`tT5tv%CJ5TAS~JG%Ir9{22g1X0f>`zSo(;yQ+xYZF)IPAl^}8Q{iD`H!4)f ziq#ACVe*}1GT0Ek{WRml&m$SOa2OG9FF8E1O_FDyUlV!^n1@<}fTm4x_$XdeACC@W zIj_lYJ8w+u%PmLK;VcmpbNCk)H(uN>F7jA5B!p+&22SY#o>;}Z&651$aPFSU18|mb zYJ)rwry6GqXEdjDGJ38ew0q~-;H)1_Ux{eAh422xH)B!^#p2WDkPJ&l7F=&}9Q6+) zO>Fu~RXWFNM{k}8q**Gq((*c!WoXdXZ#}g-x$vh6Uq#3(@4$m6JL~ypNRHRmBMuPS zm&N<4fNYd0BOP7H?Q<&0UhI+Rogw?tXsc`#otCT%kNk$M>5Icq+pFRF*+bzK>H{+y z>pK+O*zdcg+SeJbmgq4iXACbMW{i#)rE?hW56P?mUB2*ToY>Mfy_gu)^0VWNQgqo! z9DQ`y$AM%RvSe%jN5}p}I@gH{RM=V~K3qZ;P8d6Kkqsh#^NjPHLxNlwVe`@jHAg@B zwu~=ykTQt;Lxy%VI)gM2!yMBZ6%i9k$`gYi>(7quHo`$|oa0`!K|%{RalT-pB%#97 zWDDC9Q5LV9{V2keIHB;uU0@j9yXCpPls&i@62?%s<|E3G_(NY4%WUdG;BWQIpMjxO0v1 zNawUMaWS0*Ke@Pb_39CZxLE>(bZtJ6+i%$&{!$t3)UpSV1dxbNhFoo|A_em!Pu*$u~_$~z> zgb^_(Tw;8=Kuh+lMBQF=RYlv&Izs(SMWn;xLSfbQf`HFIKz4aefr#hEE^8qzJ1~z2 z4S!?%zMlR4h4JV|+U5>eYss6ge5{kbKxIdaox1#egIZxUSA8 zpTgMXod@~4yxgmThVJsFdr^gxgT6fQa5>W^@4x_@s~iq7hh_FwDCUY#aQT?uUjC}t zfT6P$RaomWj;YySVSSm&njDTf>a#^uPfiB*?PCpt7Ke*hRyRN40(S?gup4X#BkkBI z^hP(y(O%yvCvF)@I@L0eaP&| zs?M}eOx7Y}hic!0WM{>9R);(WfJ*CjqmFI?Z5rEJ+sB><5&gkJ1Jy^RhT95$1l*{hGnDWXg~U9R;9Od2}jPFRYAqJ`IDrTn#Vcmcz9o7|Kc1o@2K2fdFC{b=(K?l_Y(S2+q-uFTA2B!=iS|dTy=1rp^2>EX{}g& zQW;c$P1qmXUqPv?$k289F~v=KaFQa+8R}Qm2c{EVqSdX%MB95EyLQKxeMh>*#=^Iq zzJgq3q;-p1D#yorFV&PrJ8bMO5(2h=O8U)wCdGt?tW<-YT3913t?MfS8&>@zRe*&t z-R*z6Hqay6za}F}_+=rxy>*^cBa&~KE9M_G$pnng+Elhr4~&TDzb6K2O`=*tlmjLU z$LdM~K^PuWfAFPhT52xe&el4|{oPX&h4k5EBfJHYYwkR>4&s%NAxN;fG%vn0QM+QW z5poddT+PpV(2FINljKf%SZd-Cl%8G6HPHh`KI6k{>CS;$?eAPWux){xEZ!c^G_~YJ zD|_#h-q)12sWLw8SYunyPY)mMlXrR)d#8U^4{ao|Xh*6sF_nsBXjt=6Iww?}IYJkk z=N&%{`Hbww=0_I^pECt~fpx(+al;*Of3`a(;wc_qF}$B#rGmO3f-0M}EbI`SdymIxb zK)~K`F4|BI)v)73udXJ0IKzh&g#>~{?VOzq#sxOgR#rQkC=kY*>~HcmH@|o#x*($9zN&OVX{!Yjn%JX2uW%3> z*Y$t%ZE$mIj zKs`vhffl?bA}+T@a{o&`D1JKQ>}%qG7|~vG9vBj62!9MjwL(6ET+~QT+4cw0`Mbn4 zMNF+ti2$nkvD|62r0jJ;fGaGP2G?yNQ}3L{VYOFky6+K?ji{^HhT+ePxcgF56RhYm3IBa;eD1__=zKb81G zxHa&FnlXc&SDAn0SUD18h;927havU;brmEl3Oq?Vr5J7vmedY6#^?;XsK7%dQtv}&r1G7|vs;yiEpY51akn(F!a=S+l7f+r1*5LijNA!D)|DI%GvHCkO=g&} z!Jx6)Hc7Y(kTWgX@jPuysRKBqpQ$aS@!*9WPpUscZkOOU%JLnmsPN}^%ed-?suFPt z_TMr>0cxI01DLpNMd6Zvj{&}S)X~b7$P#r&DesbZu|AJSfU+FP0!)QRsVL>*eE0qE zar4>S_8=e|5?M?GAALhgjISILDwUO*G4cdeBacHV-f#)O$xk-CB*nWzLUx+?d?(3a zHC}pS<3T3g;!7bG=Q7-Kqg@ONQ?%dXoyW^k{>9^%ij^W9B}a<|Tyjv?p#O-nc4V+V z9|%W7m91UHIX_SDfw4R)g#Wx~b*3EDsn=kpr5R_ro%d}J=N(ZvU|{_4Iu|dNq9QRN z-|JaIK6T?j8wgB4cp_1pxe@MzV}!3rFx$~ntFf?6p;<<2c1s_oCZy+w?6w2U_k*ht^{Az5m+R@-%Bs&+95CgyDNpQn@6RCjv``) zFKp5`LPnovD8qG4bIDgbd*-saFIwz;PisiSnOUa95i}!Ya91Zs` zlGph~9?hZy<>j}MVTH0z3jS(kIrC2Y8-*1teS<5bzZ`)I-fixDG8i#@X5!Ealz#!3 zQoNFs9W%MLu9R)r`85iS>yBw}2rp2OnOF^n8F`}<1C`6!KKlVf?bA)AZyn`TIQn zL`jd&jsZPrf3>$cEs?LL(wMtnum$3BF~b$5Dms;mc^Gy^)0hZ zyv7Gt2cIY5$!xtD`=wj;4CPn-Q^K|CaN(qE^TBuLddDV9X_oQvWZ=RgjI$+FXT_

#sxzyPwrGxTALMQY^>>x!a*U%U#NhOnr`Vm+we#J5Ira%l5F?4k@WL^78<9g_!| zzykcxe_Y|jkm$g3)9?cFz40HlJ+>oDvJ8grGx0`E^^cLL(3K$JiS5}lPBlkj`17%O z`=9dVF+qIe#&O{@x7%!Ws`-ta6YAK-Z99>4B=`CU}?4oqRY zAqEk&gl>@D=F_Fo<9f;R8M(jW>>oT_KN*HnNCy%(R$MR|jQ*lEL~;nH+*OjtcaWWIpa(lIE) zcya(uggYCYJT`Gi!xjzzO>wufaa-?2_9X>b7KOELjAuo9a)A!JK)1v+2EC#szEo0c z0H0Xi_#T8X3fw3@WvhMIp4mWGdAK{yGFlNu#z?3AK3j=XO(kZ&KE>bXE;PWpTBfyl zu9*IGdHDh;+hdHAExiyi=02*p#(>_9KNXcfUhHtXCDpPN#M2EG1}xsjt-xOvXCj0X z>8Glrk#kW2+^-D{aGk{Z? zCD=GjgyWMl5ynk&k5exAx;b0F5sNFEL*Rbt;(NL-CxxX15GwiPCac{D{zvOX{9e^e zXhC>b*n{e!;t3m!m&#G)y{CS@lgS6IW9kfxw{N^4`QreYcKMZZMDXcql`r{+_&x5`&-$}b75~n3JSu;F9fs1+(3-*LJ~C4C_192BIJBbwi_rT z^y{^$_$g^*kZ{K;KPP{tcsF?i4{vs#ei^wXzZWSpO#-n9EjYu}gN(DJ%05rR4->K> z(hj9Y5BR7a0~C>0gpTROfCg8+^6VeSpUnUJLm+_aRm1M!|4J zZOHRH#_pU@YQ00Bkx;jUWnV4mlvBZw_cu^25&PBaI{_z%h%Mb)Xj{c zaUfr}?y&q-&PD(+q%}No-S<7O4IO%o0y(m#hkWZPX7dmB8rIgR<3^Z zD1r6^sfJloGfswQGnTh^Hsw)7HTR(234zh;R`!F5#Xl;y&qsB(r5uf9VoAklxs#in zl7#5M*Vg$T_&Q2JmTlpW8kZbaFbQrqqdkAdvrjZUd)Qv3TqpHavvGVcZtjD}>q%;7`$o5ptUuJ5Ku2^QOUjYhUtw9K}9z7;P8 zp>he@mlYy3s|PPy%C&5YOHyWrV-mMK?#A___~2g$W*2#l=SxLnBP%yXM%^E$A;f=v zd2r`v@4M&_s~bbhvMF1Lp|7wRgKce{e8)Q;P?zr9aXlIOO%=nRVIJw zNz4?f|&3*)GIF8dHx24qpM1UVupY5`_xNs4p zhz9t#prOl#X`xsDC9`hgy_MY7DB@>_t7#Wv4|^RZeKn=-27xC~v%>Mh>c*IzjD=zJiKxe_;DW&dS7VZn!5De3 z&2N0bfsXDqVui6szvA*uD~&6I-Rf6j+hCVJ`62L1mznL@I`T30jkkuDeWlaEDuKh6 zw6rD%gnLleyGit=f;V=47vt)9MF2O@K| zHsvgV5t|rJ>6rCsA}?SBp`vh7uunC%jmlxL4+svXlRS~C1M9`lW?6XtdXam1 zR7>SSRs8Z8VO)$B`t=$Vh?zk)r|*?<-PNb2W7?YS&U(41d#;$Uls)jlYC+Olf928M z2a-RR88rRmA%|m^c-3>VU}GgvDM8zKo$C~14&U@Q=T213g@`9*@%W_gh3_30p`km< z5)VKU0{p1Kh5RO|{a^Sa%~fKhC6zE~^G^@*SJo~lLzY0oz^nBbJE@5{d6U#Io)0E9 zf?N>kS4(D^5b3wBjqjjipa~WNIYIFHXW&1?A<4l%lJk#tkmTThZaQ>hFH3-bF`*^> iFF-J9%75$+8P?{N6Zxe#;GbI{NbSx&rGndLfBYXff0X(F literal 0 HcmV?d00001 diff --git a/branding/LESP.png b/branding/LESP.png new file mode 100644 index 0000000000000000000000000000000000000000..f1eceba14b2e003010e7db5d4f3ade9db4c0176d GIT binary patch literal 12786 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 f|4+SRCxQw0n4YM}_4eQ&FSIob?pEIU {suggestion}") diff --git a/examples/A Word Game/main.py b/examples/A Word Game/main.py new file mode 100644 index 0000000..9381a8d --- /dev/null +++ b/examples/A Word Game/main.py @@ -0,0 +1,31 @@ +from lesp import get_similar +import random + +# A list of words to choose from +words = ["apple", "banana", "orange", "grape", "melon", "cherry", "lemon", "lime", "pear", "peach"] + +# Pick a random word +word = random.choice(words) + +# Get three similar words with a similarity rate of 0.4 +similar_words = get_similar(word, similarity_rate=0.4, upto=3) + +# Add the original word to the list +similar_words.append(word) + +# Shuffle the list +random.shuffle(similar_words) + +# Print the list +print("Which of these words is not like the others?") +for i, w in enumerate(similar_words): + print(f"{i + 1}. {w}") + +# Get the user's answer +answer = int(input("Enter your answer: ")) + +# Check if the answer is correct +if similar_words[answer - 1] == word: + print("Correct!") +else: + print(f"Wrong! The correct answer is {word}.") diff --git a/examples/Similarity Score Calculator/main.py b/examples/Similarity Score Calculator/main.py new file mode 100644 index 0000000..7e3efcb --- /dev/null +++ b/examples/Similarity Score Calculator/main.py @@ -0,0 +1,49 @@ +# Import the get_similarity_score function from the lesp module +from lesp import get_similarity_score + +# Import tkinter for creating a graphical user interface +import tkinter as tk + +# Create a window +window = tk.Tk() +window.title("Word Similarity App") + +# Create a label for the first word +label1 = tk.Label(window, text="Enter the first word:") +label1.pack() + +# Create an entry for the first word +entry1 = tk.Entry(window) +entry1.pack() + +# Create a label for the second word +label2 = tk.Label(window, text="Enter the second word:") +label2.pack() + +# Create an entry for the second word +entry2 = tk.Entry(window) +entry2.pack() + +# Create a button for calculating the similarity score +button = tk.Button(window, text="Calculate") + +# Define a function for calculating the similarity score +def calculate(): + # Get the words from the entries + word1 = entry1.get() + word2 = entry2.get() + # Calculate the similarity score + score = get_similarity_score(word1, word2) + # Display the similarity score + result.config(text=f"The similarity score is {score:.2f}") + +# Bind the function to the button +button.config(command=calculate) +button.pack() + +# Create a label for displaying the similarity score +result = tk.Label(window, text="") +result.pack() + +# Start the main loop of the window +window.mainloop() diff --git a/ac/__init__.py b/lesp/__init__.py similarity index 100% rename from ac/__init__.py rename to lesp/__init__.py diff --git a/ac/autocorrect.py b/lesp/autocorrect.py similarity index 90% rename from ac/autocorrect.py rename to lesp/autocorrect.py index 22ce09f..c3c7d8a 100644 --- a/ac/autocorrect.py +++ b/lesp/autocorrect.py @@ -50,6 +50,11 @@ def get_similar_worker(args): def get_similar(word, similarity_rate, chunks=4, upto=3): if upto < 1: raise ValueError("Can only return 1 or more similar words.") + if chunks < 1: + raise ValueError("Can only split into 1 or more chunks.") + if similarity_rate < 0 or similarity_rate > 1: + raise ValueError("Similarity rate must be between 0 and 1.") + word = word.lower() similar_words = [] chunk_size = len(wordlist) // chunks