Use KM to Activate TE on already created Word Doc?

I have extensive autocorrect lists inside TextExpander (over 3000 words between them). I don’t want to have to recreate them all in KM or a Word Macro. It’s also easiest to keep updates in one app.

Is there a way that Keyboard Maestro could come to the rescue here? Is there any way that it could look at an already created Word doc and check against those lists (or run TE in a way that it would act like a new doc)?

I’m not sure I understand your request.
Are you saying that you want to replace all of the abbreviations in an existing Word doc with the expansion stored in TE?

If so, could you please provide an example of your Word doc, and the TE items to be used.

This looks very doable using AppleScript:

  1. Copy the Word doc contents in an AS variable
  2. Split into Words
  3. Get a list of TE abbreviations
  4. For each word from the MS Word doc, search the TE list
  5. IF found, replace the word in MS Word with the TE expansion

Here’s the TE AppleScript basics:

tell application "TextExpander"
	
	set snippetAbbList to abbreviation of every snippet of every group
	set snippetExp to plain text expansion of every snippet of every group
	
end tell

Thanks, JMchaelTX!

What I’m looking to to is copyedit a very long Word document. Normally, when I write, TE autocorrects on the fly. But there are times that either TE can’t because an app locks it out for β€˜security’ reasons, or the document is already in place (emailed to me).

Since I already have a folder in TE which has a ton of autocorrects for misspelled words, words that should be capped, some that should have hyphens, some that should’t, I’d like to make use of them.

Does this make better sense?

Yes. So I think you have confirmed my assertion:

So, does my simple outline of a solution above work for you?

For Step #4, I think I would do this using Word VBA:

  1. Build a 2 dimensional array using the data from the TE lists
  2. Loop on each word in the Word doc
  3. Search the array to find a TE match
  4. If found, replace with the TE expansion

Here’s a ref on VBA arrays that you may find helpful:
Getting Started with Arrays in Visual Basic for Applications

I would use a Word VBA because it can replace the text without affecting the formatting.

This is a lot of work, but definitely doable.

As you are building the scripts and macros, I’ll be glad to answer and questions that I can.

Thanks!

Yeah. I was afraid I’d have to convert them to a Word Macro. Might have to look at how TE exports, then create a KM macro to go through and modify the exported TE file so that a Word Macro can look at a separate document to run against. Typing them in all by hand would be way past excruciating.

Example of Word doc for VBA to run against:

benedryl|Benedryl
bric-brac|bric-a-brac
coffee maker|coffeemaker
cold blooded|cold-blooded

As always, use whatever tool works best for you.

In this case, it would be easy using AppleScript to get the TE snipped data (abbreviations and expanded text) and write that to a file, even a CSV file. You can then open this file using Word VBA, and load the data into VBA array.

I love KM, and use it daily. But I don’t see an obvious roll for KM in this process. Maybe Peter or Chris (ccstone) will jump in and offer alternative process that I don’t see.

I’m Apple Script Challenged. :frowning:

Hey JustRed,

JM has pretty much covered it.

If you’re dealing with plain-text then AppleScript + the Satimage.osax AppleScript extension is a viable answer. I’ve wrote a pretty sophisticated find/replace script for someone on the BBEdit-Talk list (IIRC) that does much of what you’re talking about.

If you’re dealing with styled-text then the AppleScript solution is out.

I’m wondering though if you can import your corrections into Word’s custom dictionary (not the auto-correct list). It might even be possible to do this on a per-document basis.

-Chris

I’ll look into the possibility of somehow getting those TE corrections into Word’s custom dictionary. Not quite sure how that’ll be possible as TE doesn’t seem to make it easy to extract information. Like I said, I don’t know beans about AppleScripts.

Thanks, everyone!

Hey JustRed, all of us were in that position at some point in our life. What motivated many of us to learn AppleScript was the need to automate something like your project. It’s a matter of having the right demand (need for something), and the time available to invest in learning a new tool. The payback is huge.

If you are interested in learning AppleScript, then:

If you decide to start learning AppleScript, post back here and we’ll give you some more good references.

Hey JustRed,

If you don’t have TextWrangler on your system then download and install it.

Open TextWrangler.

Open the Script Editor.app.

Paste in the AppleScript below.

Run the script.

It’ll take a couple or three minutes to complete.

-Chris

-------------------------------------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2016/02/25 16:39
# dMod: 2016/02/25 16:39 
# Appl: TextExpander
# Task: Export TextExpander Snippets to TextWrangler
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @Export, @TextExpander, @Snippets, @TextWrangler
-------------------------------------------------------------------------------------------

set _sep to "------------------------------------------------------------------"

set docSaveLocation to (path to desktop as text) & "TextExpander_Export.txt"
tell application "TextWrangler"
  if not running then run
  delay 1
  activate
  set newDoc to make new text window with properties {bounds:{0, 44, 905, 1196}} initial save location docSaveLocation
  save newDoc's document
end tell

tell application "TextExpander"
  set groupNameList to name of every group
  
  repeat with theGroup in groupNameList
    set _name to _sep & return & (contents of theGroup) & space & "Snippet Group" & return & _sep & return & return
    
    textwranglerSetNamedDocText(1, _name, "append", "don't activate") of me
    
    tell group theGroup
      repeat with theSnippet in snippets
        set theSnippetText to theSnippet's abbreviation & tab & theSnippet's plain text expansion & return
        textwranglerSetNamedDocText(1, theSnippetText & return, "append", "don't activate") of me
      end repeat
    end tell
    
  end repeat
  
end tell

-------------------------------------------------------------------------------------------
--Β» HANDLERS
-------------------------------------------------------------------------------------------
on textwranglerSetNamedDocText(_document, _text, _append, _activate)
  tell application "TextWrangler"
    
    if _document = 0 or _document = "new" then
      set newDoc to make new document with properties {text:_text, bounds:{303, 44, 1617, 1196}}
      
    else if _append = true or _append = "append" or _append = 1 then
      set after text of text document _document to _text
    end if
    
    if _activate = 1 or _activate = "activate" then activate
    
  end tell
end textwranglerSetNamedDocText
-------------------------------------------------------------------------------------------

OK, Red, this is your lucky day! :astonished:

See Script Below

I got interested in this as a learning exercise, and I have written the below script which should give you a big jumpstart.

I took a completely different approach from what I suggested earlier:

  1. It is 100% AppleScript
  2. It loads your MS Word document into a AppleScript variable, which is a list of words (defined as being separated by a space
  3. It then uses each word to lookup a snippet in TextExpander
  4. If it finds a snippet, it returns the plain text expansion of the snippet.
  5. AND, the final step will be for you to complete:
    Use the MS Word Find and Replace method to find the word, and replace with the snippet returned in step #4.

To get started:

  1. Open a COPY of your Word doc to be used for testing
  2. Open the Script Editor and paste in the below code
    (be sure to change the language to "AppleScript"
  3. Compile the code (CMD-K)
  4. SAVE the script (CMD-S)
  5. RUN the script (CMD-R)

You will see the results at the bottom of the script window. You may need to click on the the rectangle that looks like a note: , and then on the button.

I think this will run quite fast. The script has a timer in it, so you can see how long it takes. In my test, it processed 186 words in 0.6 sec. The lookup of the snippet in TE using AppleScript seems quite fast.

To write the AppleScript for the MS Word Find & Replace, you can start by doing a google on "microsoft word AppleScript replace". To learn the MS Word object model, open its scripting dictionary in Script Editor: CMD-SHIFT-O, then scroll down to "Microsoft Word", and double click on it.

If you have any questions along the way, just post here, and I'm sure either I or @ccstone (Chris) will answer.

Good luck, and let us know how it goes.

@ccstone, please jump in if you see any issues, or have suggestions for improvement.

(*
===============================================================================
	[WORD] Replace Abbreviations in Word Doc with TextExpander Snippet
===============================================================================

VER: 	1.0		LAST UPDATE:   2016-02-25

PURPOSE:
	β€’ Process every word in a MS Word document, and replace with the Snippet
		plain text expansion in TextExpander, IF the word exists as an Abbreviation.

AUTHOR:		JMichaelTX
					Find any bugs/issues or have suggestions for improvement?
					Contact me via PM or at blog.jmichaeltx.com/contact/

REQUIRED:
	1.	Mac OS X Yosemite 10.10.5+
	2.	Mac Applications
				β€’ Microsoft Word 2011 Mac
				β€’ TextExpander 5.1.4
				
	3.	EXTERNAL OSAX Additions/LIBRARIES/FUNCTIONS
				β€’ NONE
					
	4.	INTERNAL FUNCTIONS:
				β€’ on getTESnippet(pAbbreviationStr)
				β€’ on collapseList(pMultiList)
				β€’ on splitStrToList(pString, pDelim)
				β€’ on joinListToStr(pList, pDelim)
				β€’ on continueScript(pMsgStr)
				β€’ on timer(pAction)
				β€’ on trimThis(pstrSourceText, pstrCharToTrim, pstrTrimDirection)


REF:  The following were used in some way in the writing of this script.
	1.	
===============================================================================
   
*)
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

timer("start")

tell application "Microsoft Word"
	tell active document
		set theContent to content of text object
		--log theContent
		
		set contentParagraphs to paragraphs of theContent
		set {astid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " "}
		set theContent to contentParagraphs as text
		--log theContent
		--set wordList to my splitStrToList(theContent, linefeed)
		--set theContent to my joinListToStr(wordList, " ")
		set wordList to my splitStrToList(theContent, " ")
		
		set numWords to count of wordList
		log "numWords: " & numWords
		
		repeat with iWord from 1 to numWords
			
			set wordStr to item iWord of wordList
			set wordStr to my trimThis(wordStr, true, "full")
			
			if wordStr β‰  "" then
				--log "[" & iWord & "]: " & "WORD: " & wordStr
				set snippetStr to my getTESnippet(wordStr)
			else
				set snippetStr to ""
			end if
			
			--- REPLACE ABBREVIATION IN WORD DOC IF FOUND ---
			
			if snippetStr β‰  "" then
				
				log ("[" & iWord & "]: " & "ABBREVIATION FOUND: " & wordStr)
				
				display notification Β¬
					"Replacing Abbreviation in Word Doc with TE Expansion" with title (name of me)
				
				--- FIND & REPLACE IN WORD DOC ---
				
				#### TODO:  ADD CODE FOR FIND & REPLACE ###
				
			end if
			
		end repeat -- Word List
		
	end tell
	
end tell

timer("STOP")

###β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€” END OF MAIN SCRIPT β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#			getTESnippet()			Get Plain Text Expansion of TextExpander Snippet
#
#			Ver 1.0		2016-02-25
###β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”

on getTESnippet(pAbbreviationStr)
	
	--log "getTESnippet() called with: " & pAbbreviationStr
	
	tell application "TextExpander"
		
		if pAbbreviationStr β‰  "" then
			
			set abbStr to pAbbreviationStr -- Example:";km"
			set snippetMultiList to every snippet of every group whose abbreviation is abbStr
			set snippetList to my collapseList(snippetMultiList)
			
			if snippetList β‰  {} then
				set oSnippet to item 1 of snippetList ### ASSUMES only 1 matching Snippet
				set snippetStr to plain text expansion of oSnippet ---> THIS is what I'm after.
			else
				set snippetStr to "" -- IF Snippet NOT Found, set to empty string
			end if
			
		else
			set snippetStr to ""
			
		end if -- pAbbreviationStr β‰  ""
		
	end tell -- TextExpander
	
	return snippetStr
	
end getTESnippet -- function getTESnippet
###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#			collapseList()			Collapse List of Lists to One List with NO Empty Items
#
#			Ver 1.0		2016-02-25
###β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”

on collapseList(pMultiList)
	
	set singleList to {}
	
	repeat with ndx1 in pMultiList
		
		if contents of ndx1 is not {} then
			
			repeat with ndx2 in ndx1
				set end of singleList to contents of ndx2
			end repeat -- ndx2
			
		end if
	end repeat -- ndx1
	
	set pMultiList to {}
	
	return singleList
	
end collapseList
###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on splitStrToList(pString, pDelim)
	--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	set textDelimSave to AppleScript's text item delimiters
	set AppleScript's text item delimiters to pDelim
	
	set newList to text items of pString
	
	set AppleScript's text item delimiters to textDelimSave
	
	return newList
	
end splitStrToList

--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on joinListToStr(pList, pDelim)
	--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	set textDelimSave to AppleScript's text item delimiters
	set AppleScript's text item delimiters to pDelim
	
	set newString to pList as string
	
	set AppleScript's text item delimiters to textDelimSave
	
	return newString
	
end joinListToStr
###β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
#			continueScript()			Prompt User to Continue or Not
#
#			Ver 2.1								2016-02-21
###β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”

on continueScript(pMsgStr)
	
	beep
	
	set titleStr to (name of me) & "

" & pMsgStr & "


" & "Continue or Cancel?"
	
	
	set recAns to (display alert titleStr as critical Β¬
		buttons {"Cancel", "Continue"}) -- last button is default
	set strAns to button returned of recAns
	
	if (strAns = "Continue") then
		set continueBol to true
	else
		set continueBol to false
	end if
	
	return continueBol
	
end continueScript
###β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”

###β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
#			timer()		Calculate and Log Execution Time
#
#			Ver 1.0		2016-02-21
#
#			REF:  The base ASObjC code was provided by Shane Stanley
###β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”

on timer(pAction)
	(*
	### Requires these two statements at top of main script: ###
		 	use scripting additions
		 	use framework "Foundation"
*)
	global gTimerStartDate
	if (pAction = "start") then
		set gTimerStartDate to current application's NSDate's |date|()
		log "START: " & ((current date) as text)
	else
		log pAction & ":  
    β€’ " & ((current date) as text) & "
    β€’ EXECUTION TIME: " & (round (-(gTimerStartDate's timeIntervalSinceNow())) * 1000) / 1000.0 & " sec"
	end if
end timer

###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#		trimThis()			Trim (remove) Characters from Left and/or Right of String
#
#		Ver 1.0		       2016-02-25
#		AUTHOR:          Shane Stanley
#		REF:             MacScripter / Trim [Remove Spaces]
#											 http://macscripter.net/viewtopic.php?pid=182209#p182209
#  PARAMETERS:
#		β€’ pstrCharToTrim    : A list of characters to trim, or true to use default
#		β€’ pstrSourceText    : The text to be trimmed
#		β€’ pstrTrimDirection : Direction of Trim left, right or any value for full
###β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”

on trimThis(pstrSourceText, pstrCharToTrim, pstrTrimDirection)
	
	
	if pstrCharToTrim = missing value or pstrCharToTrim = true then
		-- SPACE, TAB, RETURN, newline characters (U+000A–U+000D, U+0085)
		-- Equiv to: ASCII character 10, return, ASCII character 0
		
		set setToTrim to current application's NSCharacterSet's whitespaceAndNewlineCharacterSet()
	else
		set setToTrim to current application's NSCharacterSet's characterSetWithCharactersInString:pstrCharToTrim
	end if
	
	set anNSString to current application's NSString's stringWithString:pstrSourceText
	
	if pstrTrimDirection = left then
		
		set theRange to anNSString's rangeOfCharacterFromSet:(setToTrim's invertedSet())
		if |length| of theRange = 0 then return ""
		set anNSString to anNSString's substringFromIndex:(theRange's location)
		
	else if pstrTrimDirection = right then
		set theRange to anNSString's rangeOfCharacterFromSet:(setToTrim's invertedSet()) options:(current application's NSBackwardsSearch)
		if |length| of theRange = 0 then return ""
		set anNSString to anNSString's substringToIndex:(theRange's location)
		
	else
		set anNSString to anNSString's stringByTrimmingCharactersInSet:setToTrim
	end if
	
	return anNSString as text
end trimThis
###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 Like

Once again Satimage surfaces. :wink:
So Chris, are you using any custom GUIs? I was reading the Satimage documentation and it appears they offer some tools for making them.
This verges on making Apps and the GUI windows look like some windows I have seen before.

Hey John,

I thought I responded to this…

Custom dialogs and such may be created with SMILE but not the Satimage.osax.

http://www.satimage.fr/software/en/downloads/index.html

Smile’s find dialog is a good example.

-Chris

1 Like