v2 of Google "Did you mean..." tool? Topic is solved
v2 of Google "Did you mean..." tool?
I've been using this v1 function written by TheDewd viewtopic.php?f=6&t=83164#p364301. It is a tool to check spelling of a word (or, I guess, grammar of a phrase). A google search finds several different versions of this, but I can't find any that are written for AHK v2. I tried the v1 to v2 converter, but it doesn't work for this.
Do you guys know if this is already available online? Or... If anyone is up for the challenge...
Do you guys know if this is already available online? Or... If anyone is up for the challenge...
ste(phen|ve) kunkel
Re: v2 of Google "Did you mean..." tool? Topic is solved
Code: Select all
#Requires AutoHotkey v2.0
MsgBox GoogleAutoCorrect('Helllo Worlpd')
GoogleAutoCorrect(word) {
objReq := ComObject('WinHttp.WinHttpRequest.5.1')
objReq.Open('GET', 'https://www.google.com/search?q=' word)
objReq.SetRequestHeader('User-Agent'
, 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)')
objReq.Send(), HTML := objReq.ResponseText
RegExMatch(HTML, 'value="(.*?)"', &A)
RegExMatch(HTML, ';spell=1.*?>(.*?)<\/a>', &B)
Return B[1] || A[1]
}
Re: v2 of Google "Did you mean..." tool?
Awesome! Thanks Mike! I'm going to use this in a project right now.
ste(phen|ve) kunkel
Re: v2 of Google "Did you mean..." tool?
This v2 code mostly works, but I'm getting an odd error occasionally...
Anyone have thoughts on a solution?
It's always the same string, "__Item". I don't know if it's a problem with the function, or a glitch with Google. The full code is below, but the relevant part is just lines 344 - 352. The function that calls the google function appears directly above it. My tool is a "hotstring helper" so the idea is to select some text then hit the hotkey (!#h). The google function works fine under that normal condition--however: Run the script, don't select any text, press hotkey. Then type a misspelled word into the 'replacment text' edit box. Then press the Spell button. (The dialogs might appear behind the main gui.) The error doesn't seem to appear every time either--not reliably reproducible....Error: This value of type "String" has no property named "__Item".
342: RegExMatch(HTML, 'value="(.*?)"', &A)
343: RegExMatch(HTML, ';spell=1.*?>(.*?)<\/a>', &B)
▶ 344: Return B[1] || A[1]
345: }
348: {
Call stack:
S:\AutoHotkey\MasterScript\@HotStrHelpML for v2\HH - Multi For v2.ahk (344) : [GoogleAutoCorrect] Return B[1] || A[1]
S:\AutoHotkey\MasterScript\@HotStrHelpML for v2\HH - Multi For v2.ahk (318) : [hhButtonSpell] googleSugg := GoogleAutoCorrect(tRepStr)
Anyone have thoughts on a solution?
Code: Select all
#SingleInstance
#Requires AutoHotkey v2.0
;------------------------------------------------------------------------------
; Hotstring Helper - Mulitline
;------------------------------------------------------------------------------
; By Kunkel321, with much help from forum members and others. Version 8-7-2023
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=114688
; A version of Hotstring Helper that will support block multi-line replacements.
; Customization options are present throughout, and are flagged as such.
; Needs AHK v2. Partly auto-converted from v1, partly rewritten.
; Please get a copy of AutoHotkey.exe (v2) and rename it to match the name of this
; script file, so that the .exe and the .ahk have the same name, in the same folder.
; DO NOT COMPILE, or the Append command won't work. Keep at bottom of AutoExecute
; section of your script. The Gui stays in RAM, but gets repopulated upon
; hotkey press. Remove these comments as desired.
;==Change=colors=as=desired========================
GuiColor := "F0F8FF" ; "F0F8FF" is light blue
FontColor := "003366" ; "003366" is dark blue
;==================================================
Global hFactor := 0 ; Don't change size here. Change in TogSize() function, below.
Global wFactor := 0 ; Don't change here. Change in TogSize() function.
FormName := "Hotstring Helper -- Muli-Line" ; Change here, if desired.
hh := Gui('', FormName)
hh.Opt("-MinimizeBox +alwaysOnTop")
hh.BackColor := GuiColor
hh.SetFont("s11 c" . FontColor)
; ----- Trigger string parts
hh.AddText('y4 w30', 'Options')
hh.AddText('vTrigStrLbl x+20 w250', 'Trigger String')
hh.AddEdit('vMyDefaultOpts yp+20 xm+10 w30 h24')
DefHotStr := hh.AddEdit('vDefHotStr x+28 w' . wFactor + 250, '')
; ----- Replacement string parts
hh.AddText('xm', 'Enter Replacement String')
hh.SetFont('s9')
hh.AddButton('vSizeTog x+5 yp-5 h8 +notab', 'Make Bigger').OnEvent("Click", TogSize)
hh.AddButton('vSymTog x+5 h8 +notab', '+ Symbols').OnEvent("Click", TogSym)
hh.SetFont('s11')
;RepStr := hh.AddEdit('vRepStr +Wrap yp+25 xs h' . hFactor + 100 . ' w' . wFactor + 320, '')
RepStr := hh.AddEdit('vRepStr +Wrap y+1 xs h' . hFactor + 100 . ' w' . wFactor + 320, '')
ComLbl := hh.AddText('xm y' . hFactor + 182, 'Enter Comment')
ComStr := hh.AddEdit('vComStr xs y' . hFactor + 200 . ' w' . wFactor + 315)
; ---- Buttons
(ButApp := hh.AddButton('xm y' . hFactor + 234, '&Append')).OnEvent("Click", hhButtonAppend)
(ButVal := hh.AddButton('+notab x+5 y' . hFactor + 234, '&Validate')).OnEvent("Click", hhButtonValidate)
(ButSpell := hh.AddButton('+notab x+5 y' . hFactor + 234, '&Spell')).OnEvent("Click", hhButtonSpell)
(ButOpen := hh.AddButton('+notab x+5 y' . hFactor + 234, '&Open')).OnEvent("Click", hhButtonOpen)
(ButCancel := hh.AddButton('+notab x+5 y' . hFactor + 234, '&Cancel')).OnEvent("Click", hhButtonCancel)
; The below hotkey also marks the end of the AutoExecution Section of this script file.
!#h:: ; HotString Helper activation hotkey-combo (not string) is Win+h. Change if desired.
{ MyDefaultOpts := ""
DefaultHotStr := ""
DefHotStr := ""
LBLhotstring := ""
SizeTog := ""
addFirstLetters := ""
tooSmallLen := ""
Global myPrefix := ""
Global mySuffix := ""
initials := ""
HotStrSug := ""
Global tMyDefaultOpts := ""
Global tDefHotStr := ""
Global tRepStr := ""
Global tComStr := ""
Global ClipboardOld := ClipboardAll() ; Save and put back later.
A_Clipboard := "" ; Must start off blank for detection to work.
Send("^c") ; Copy selected text.
Errorlevel := !ClipWait(0.3) ; Wait for clipboard to contain text.
If !InStr(A_Clipboard, "`n") ; Only trim NON multi line text strings.
A_Clipboard := Trim(A_Clipboard) ; Because MS Word keeps leaving spaces.
; If white space present in selected text, probably not an Autocorrect entry.
If (InStr(A_Clipboard, " ") || InStr(A_Clipboard, "`n"))
{
;=======Change=options=for=MULTI=word=entry=options=and=trigger=strings=as=desired==============
MyDefaultOpts := "" ; PreEnter these multi-word hotstring options; "*" = end char not needed, etc.
myPrefix := ";" ; Optional character that you want suggested at the beginning of each hotstring.
addFirstLetters := 5 ; Add first letter of this many words. (5 recommended; 0 = don't use feature.)
tooSmallLen := 2 ; Only first letters from words longer than this. (Moot if addFirstLetters = 0)
mySuffix := "" ; An empty string "" means don't use feature.
;===========================================================one=more=below=======================
If (addFirstLetters > 0)
{ LBLhotstring := "Edit trigger string as needed"
initials := "" ; Initials will be the first letter of each word as a hotstring suggestion.
HotStrSug := StrReplace(A_Clipboard, "`n", " ") ; Unwrap, but only for hotstr suggestion.
Loop Parse, HotStrSug, A_Space
{ If (Strlen(A_LoopField) > tooSmallLen) ; Check length of each word, ignore if N letters.
initials :=initials . SubStr(A_LoopField, ("1")<1 ? ("1")-1 : ("1"), "1")
If (StrLen(initials) = addFirstLetters) ; stop looping if hotstring is N chars long.
break
}
initials := StrLower(initials)
DefaultHotStr := myPrefix . initials . mySuffix ; Append preferred prefix or suffix, as defined above, to initials.
}
else
{LBLhotstring := "Add a trigger string"
DefaultHotStr := myPrefix . mySuffix ; Use prefix and/or suffix as needed, but no initials.
}
}
Else If (A_Clipboard = "")
LBLhotstring := "Add a trigger string"
else
{ LBLhotstring := "Add misspelled word"
DefaultHotStr := A_Clipboard ; No spaces found so assume it's a mispelling autocorrect entry: no pre/suffix.
;===============Change=options=AUTOCORRECT=words=as=desired======================================
myDefaultOpts := "" ; PreEnter these (single-word) autocorrect options; "T" = raw text mode, etc.
;================================================================================================
}
hh['MyDefaultOpts'].value := MyDefaultOpts
hh['TrigStrLbl'].value := LBLhotstring
hh['DefHotStr'].value := DefaultHotStr
hh['RepStr'].value := A_Clipboard
hh['RepStr'].Opt("-Readonly")
ButApp.Enabled := true
hh.Show('Autosize')
} ; bottom of hotkey function
TogSize(*)
{ If (hh['SizeTog'].text = "Make Bigger") {
hh['SizeTog'].text := "Make Smaller"
; ======Change=size=of=GUI=when="Make Bigger"=is=envoked========
hFactor := 200 ; Height of Replacement box, Y pos of things below it.
wFactor := 200 ; Width of 3 of the edit boxes.
;===============================================================
SubTogSize(hFactor, wFactor)
hh.Show('Autosize Center')
return
}
If (hh['SizeTog'].text = "Make Smaller") {
hh['SizeTog'].text := "Make Bigger"
SubTogSize(0, 0)
hh.Show('Autosize')
return
}
SubTogSize(hFactor, wFactor)
{
DefHotStr.Move(,, wFactor + 250,)
RepStr.Move(,, wFactor + 320, hFactor + 100)
ComLbl.Move(, hFactor + 182,,)
ComStr.move(, hFactor + 200, wFactor + 315,)
ButApp.Move(, hFactor + 234,,)
ButVal.Move(, hFactor + 234,,)
ButSpell.Move(, hFactor + 234,,)
ButOpen.Move(, hFactor + 234,,)
ButCancel.Move(, hFactor + 234,,)
}
}
TogSym(*)
{ ;====assign=symbolss=for="show symb"=button=================================
myPilcrow := "¶" ; Okay to change symb here if desired.
myDot := "• " ; adding a space allows more natural wrapping.
myTab := " ? "
;===========================================================================
If (hh['SymTog'].text = "+ Symbols") {
hh['SymTog'].text := "- Symbols"
RepStr := hh['RepStr'].text
RepStr := StrReplace(StrReplace(RepStr, "`r`n", "`n"), "`n", myPilcrow . "`n") ; Pilcrow for Enter
RepStr := StrReplace(RepStr, A_Space, myDot) ; middle dot for Space
RepStr := StrReplace(RepStr, A_Tab, myTab) ; space arrow space for Tab
hh['RepStr'].value := RepStr
hh['RepStr'].Opt("+Readonly")
ButApp.Enabled := false
hh.Show('Autosize')
return
}
If (hh['SymTog'].text = "- Symbols") {
hh['SymTog'].text := "+ Symbols"
RepStr := hh['RepStr'].text
RepStr := StrReplace(RepStr, myPilcrow . "`r", "`r") ; Have to use `r ... weird.
RepStr := StrReplace(RepStr, myDot, A_Space)
RepStr := StrReplace(RepStr, myTab, A_Tab)
hh['RepStr'].value := RepStr
hh['RepStr'].Opt("-Readonly")
ButApp.Enabled := true
hh.Show('Autosize')
return
}
}
#HotIf WinActive(FormName, ) ; Allows window-specific behavior.=============================
{
$Enter:: ; When Enter is pressed, but only in this GUI. "$" prevents accidental Enter key loop.
{
If (hh['SymTog'].text = "Hide Symb")
return
Else if RepStr.Focused {
Send("{Enter}") ; Just normal typing; Enter yields Enter key press.
Return
}
Else {
hhButtonAppend() ; Replacement box not focused, so press Append button.
return
}
}
Esc::
{
hh.Hide()
A_Clipboard := ClipboardOld
}
}
#HotIf ; Turn off window-specific behavior.======================
hhButtonAppend(*)
{ tMyDefaultOpts := hh['MyDefaultOpts'].text
tDefHotStr := hh['DefHotStr'].text
tRepStr := hh['RepStr'].text
ValidationFunction(tMyDefaultOpts, tDefHotStr, tRepStr)
If Not InStr(CombinedValidMsg, "-Okay.",,, 3)
{ ; Msg doesn't have three occurrences of "-Okay."
msgResult := MsgBox(CombinedValidMsg "`n`n####################`nContinue Anyway?", "VALIDATION", "OC 4096" )
if (msgResult = "OK") {
Appendit(tMyDefaultOpts, tDefHotStr, tRepStr) ; not valid, but user chose to continue anyway
return
}
else
return ; not valid, and user cancelled
}
else { ; no validation problems found
Appendit(tMyDefaultOpts, tDefHotStr, tRepStr)
return
}
}
hhButtonValidate(*)
{ tMyDefaultOpts := hh['MyDefaultOpts'].text
tDefHotStr := hh['DefHotStr'].text
tRepStr := hh['RepStr'].text
ValidationFunction(tMyDefaultOpts, tDefHotStr, tRepStr)
MsgBox("Validation Results`n#################`n" . CombinedValidMsg,, 4096)
Return
}
ValidationFunction(tMyDefaultOpts, tDefHotStr, tRepStr)
{ Global CombinedValidMsg
ThisFile := Fileread(A_ScriptName) ; Save these contents to variable 'ThisFile'.
; ThisFile := Fileread("S:\AutoHotkey\MasterScript\MasterScript.ahk") ; <---- CHANGE later
If (tMyDefaultOpts = "") ; If options box is empty, skip regxex check.
validOpts := "Okay."
else { ;===== Make sure hotstring options are valid ========
NeedleRegEx := "(\*|B0|\?|SI|C|K[0-9]{1,3}|SE|X|SP|O|R|T)" ; These are in the AHK docs I swear!!!
WithNeedlesRemoved := RegExReplace(tMyDefaultOpts, NeedleRegEx, "") ; Remove all valid options from var.
If(WithNeedlesRemoved = "") ; If they were all removed...
validOpts := "Okay."
else { ; Some characters from the Options box were not recognized.
OptTips := " ; Just a block text assignement to var
(
Don't include the colons.
..from AHK v1 docs...
* - ending char not needed
? - trigger inside other words
B0 - no backspacing
SI - send input mode
C - case-sensitive
K(n) - set key delay
SE - send event mode
X - execute command
SP - send play mode
O - omit end char
R - send raw
T - super raw
)"
validOpts := "Invalid Hotsring Options found.`n---> " . WithNeedlesRemoved . "`n`n`tTips:`n" . OptTips
}
}
;==== Make sure hotstring box content is valid ========
validHot := "" ; Reset to empty each time.
If (tDefHotStr = "") || (tDefHotStr = myPrefix) || (tDefHotStr = mySuffix) || InStr(tDefHotStr, ":")
validHot := "HotString box should not be empty.`n-Don't include colons."
else ; No colons, and not empty. Good. Now check for duplicates.
Loop Parse, ThisFile, "`n", "`r" ; Check line-by-line.
If instr(A_LoopField, ":" . tDefHotStr . "::") { ; If line contains tDefHotStr...
validHot := "DUPLICATE FOUND`nAt Line " . A_Index . ":`n " . A_LoopField
break
}
If (validHot = "") ; If variable didn't get set in loop, then no duplicates found
validHot := "Okay."
;==== Make sure replacement string box content is valid ===========
If (tRepStr = "") || (SubStr(tRepStr, ("1")<1 ? ("1")-1 : ("1"), "1")==":") ; If Replacement box empty, or first char is ":"
validRep := "Replacement string box should not be empty.`n-Don't include the colons."
else
validRep := "Okay."
; Concatenate the three above validity checks.
CombinedValidMsg := "OPTIONS BOX `n-" . validOpts . "`n`nHOTSTRING BOX `n-" . validHot . "`n`nREPLACEMENT BOX `n-" . validRep
Return CombinedValidMsg ; return result for use is Append or Validation functions.
} ; end of validation func
Appendit(tMyDefaultOpts, tDefHotStr, tRepStr)
{ WholeStr := ""
tMyDefaultOpts := hh['MyDefaultOpts'].text
tDefHotStr := hh['DefHotStr'].text
tRepStr := hh['RepStr'].text
tComStr := hh['ComStr'].text
If (tComStr != "")
tComStr := " `; " . tComStr
If InStr(tRepStr, "`n") {
WholeStr := ":" . tMyDefaultOpts . ":" . tDefHotStr . "::" . tComStr . "`n(`n" . tRepStr . "`n)"
}
Else {
WholeStr := ":" . tMyDefaultOpts . ":" . tDefHotStr . "::" . tRepStr . tComStr
}
FileAppend("`n" WholeStr, A_ScriptFullPath) ; 'n makes sure it goes on a new line.
Reload() ; relaod the script so the new hotstring will be ready for use.
}
hhButtonSpell(*) ; Called is "Spell" because "Spell Check" is too long.
{ tRepStr := hh['RepStr'].text
If (tRepStr = "")
MsgBox("Replacement Text not found.",, 4096)
else {
googleSugg := GoogleAutoCorrect(tRepStr) ; Calls below function
If (tRepStr = googleSugg)
MsgBox("No suggestions found.",, 4096)
Else {
msgResult := MsgBox(googleSugg "`n`n######################`nChange Replacement Text?", "Google Suggestion", "OC 4096")
if (msgResult = "OK")
hh['RepStr'].value := googleSugg
else
return
}
}
}
GoogleAutoCorrect(word)
{ ; Original by TheDewd, converted to v2 by Mikeyww.
; autohotkey.com/boards/viewtopic.php?f=82&t=120143
objReq := ComObject('WinHttp.WinHttpRequest.5.1')
objReq.Open('GET', 'https://www.google.com/search?q=' word)
objReq.SetRequestHeader('User-Agent'
, 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)')
objReq.Send(), HTML := objReq.ResponseText
RegExMatch(HTML, 'value="(.*?)"', &A)
RegExMatch(HTML, ';spell=1.*?>(.*?)<\/a>', &B)
Return B[1] || A[1]
}
hhButtonOpen(*)
{ ; Open this file and go to the bottom so you can see your Hotstrings.
hh.Hide()
A_Clipboard := ClipboardOld ; Restore previous contents of clipboard.
Edit()
WinWaitActive(A_ScriptName) ; Wait for the script to be open in text editor.
Sleep(250)
Send("{Ctrl Down}{End}{Ctrl Up}{Home}") ; Navigate to the bottom.
}
hhButtonCancel(*)
{ hh.Hide()
A_Clipboard := ClipboardOld ; Restore previous contents of clipboard.
}
; HotStrings will be appended (added) by the script at the bottom.
;HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
::;ottff:: ; just a test...
(
one two
three four
five six
seven eight
nine ten.
)
ste(phen|ve) kunkel
Re: v2 of Google "Did you mean..." tool?
Regarding the error, you can see this if your string introduces a problem for RegExMatch.
Of course, one can readily check for such a condition.
Code: Select all
#Requires AutoHotkey v2.0
RegExMatch('', '(.)', &m)
MsgBox m[1]
Code: Select all
#Requires AutoHotkey v2.0
If RegExMatch('', '(.)', &m)
MsgBox m[1]
Re: v2 of Google "Did you mean..." tool?
Yep... That's the one! If I'm reading this correctly, RegExMatch doesn't like having a blank haystack. LOL.
In the google function, it is the returned HTML code that is used for the haystack... So I'm wondering it this is getting caused by a bad internet connection.
I'll experiment. Thanks Mike!
ste(phen|ve) kunkel
Re: v2 of Google "Did you mean..." tool?
Yes, if HTML is null (e.g., nothing returned), you may see this.
Re: v2 of Google "Did you mean..." tool?
Yeah, I thought it was caused by typing a misspelled word into the gui after .show()ing it, but it wasn't that. It is that, if the searched-for string is so short that google doesn't have any "did you mean..." recommendations, then there is an error. Putting If in front of the two RegExMatches causes the function to return a blank string and prevents the error.
ste(phen|ve) kunkel
Re: v2 of Google "Did you mean..." tool?
I've never seen this before. It works great for my language too. Thanks.