Thursday, November 23, 2017
  • Index
  •  » Code Exchange
  •  » TextEdit Script to Find/Replace anything that is NOT the given string

#1 2015-04-21 01:54:21 pm

tootall8888
Member
Registered: 2015-04-21
Posts: 7

TextEdit Script to Find/Replace anything that is NOT the given string

I feel like giving back to AppleScript community.  I recently wrote this script
to run from in TextEdit.

Applescript:


--Before running this, user should have an open document in TextEdit
--and some of the text should be highlighted.
--This script takes the currently selected text in an opened file in TextEdit
--and replaces any string of characters that is not the string(s) the user specified
--with a user-specified replacement string.
--Example: User specifies the script replace anything that is not "the"
--inside the text "the people and the dogs" with the replacement "----" .
--The resulting modified text is "the----the----"
--User also has option to specify multiple strings of text by clicking "Add More".
--Example: User specifies the script replace anything that is not "people" and "dogs"
--inside the text "the people and the dogs" with the replacement "----" .
--The resulting modified text is "----people----dogs"
--User also has option of entering special constants "(alpha)", "(digit)", "(alphadigit)",
--and "(invisibles)" when asked for text to not replace. You can create more constants inside
--the function replaceAnythingThatIsNot() if you want. Add the value of each constant to
--the list in specialConstantValues.
--If you want, you can replace "TextEdit" in the code with the name of any other word-processing
--application you might want to use instead.

--MAIN ROUTINE:
tell application "TextEdit" to activate
--Copy the currently selected text:
tell application "System Events"
   tell process "TextEdit"
       click menu item "Copy" of the menu "Edit" of menu bar 1
   end tell
end tell
tell application "TextEdit"
   --Get the currently copied text:
   set theString to (the clipboard)
   set stringOrList to {}
   set theResult to display dialog "Enter specific text to NOT replace:" default answer ¬
       "" with title "TextEdit" buttons {"Cancel", "Add More", "Continue"} default button 3 cancel button 1
   set end of stringOrList to theResult's text returned
   set soFarList to "\"" & my LI(1, stringOrList) & "\""
   repeat while theResult's button returned is "Add More"
       set theResult to display dialog "Items so far:" & return & soFarList & return & ¬
           "Enter specific text to NOT replace:" default answer ¬
           "" with title "TextEdit" buttons {"Cancel", "Add More", "Continue"} ¬
           default button 3 cancel button 1
       set end of stringOrList to theResult's text returned
       set soFarList to (soFarList & "\n" & "\"" & my LI((count of stringOrList), stringOrList)) & "\""
   end repeat
   set theResult to display dialog ¬
       "Enter the new text to replace with:" default answer "" with title ¬
       "TextEdit" buttons {"Cancel", "Go"} default button 2 cancel button 1
   set replaceString to theResult's text returned
   --Modify the copied text:
   set newString to my replaceAnythingThatIsNot(stringOrList, replaceString, theString)
   --Replace the originally copied text with the new text:
   set the clipboard to newString
end tell
--Paste new text into open document:
tell application "System Events"
   tell process "TextEdit"
       click menu item "Paste and Match Style" of the menu "Edit" of menu bar 1
   end tell
end tell
--End of MAIN ROUTINE.


--Required subroutines:

(* This searches for instances of stringOrList inside theString,
and if found, replaces any sequence of characters
in between them with the replaceString.    
*)

on replaceAnythingThatIsNot(stringOrList, replaceString, theString)
   --Check for special constants:
   set specialConstantValues to {{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o"} & ¬
       {"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}, {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}, ¬
       {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o"} & ¬
       {"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"} & ¬
       {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}, {"\r", "\n", " ", "\t"}}
   set specialConstants to {"(alpha)", "(digit)", "(alphadigit)", "(invisibles)"}
   set newList to {}
   repeat with i from 1 to (count of specialConstants)
       if stringOrList contains (LI(i, specialConstants)) then
           set theIxs to item 1 of getIndex(LI(i, specialConstants), stringOrList)
           setLI(theIxs, stringOrList, LI(i, specialConstantValues))
       end if
   end repeat
   ---Convert stringOrList into a single list:
   repeat with i from 1 to (count of stringOrList)
       set newList to (newList & (LI(i, stringOrList)))
   end repeat
   set stringOrList to newList
   set {textList, newList, x, z} to {explode(theString, stringOrList), {""}, 0, 1}
   repeat
       if ((count of textList) = 1) then
           if (LI(1, textList) is not "") then set end of newList to ""
           exit repeat
       end if
       set x to (x + (count of (LI(1, textList))) + z)
       if (LI(1, textList) is "") then
           if class of stringOrList is text then
               setLI(-1, newList, (LI(-1, newList) & stringOrList))
           else if class of stringOrList is list then
               set {y, z, appendItem} to findEndCharPosition(theString, x, stringOrList)
               setLI(-1, newList, (LI(-1, newList) & appendItem))
           end if
       else
           if class of stringOrList is text then
               set end of newList to stringOrList
           else if class of stringOrList is list then
               set {y, z, appendItem} to findEndCharPosition(theString, x, stringOrList)
               set end of newList to appendItem
           end if
       end if
       set textList to LI({2, -1}, textList)
   end repeat
   set newString to implode(newList, replaceString)
   return newString
end replaceAnythingThatIsNot



on getIndex(theItem, theList)
   if class of theList is not in {integer, real, text, list} then return false --function stops.
   --If theList is a number then coerce into text:
   if (count of theList) is 0 then set theList to (theList as text)
   if theItem is not in theList then return false -- function stops.
   --Else, theItem must be in theList, so:    
   set indexList to {}
   set itemLength to (count of (theItem as text))
   if (count of theList) is 1 then -- Then theItem IS theList.
       set end of indexList to 1
       return indexList -- function stops.
   end if
   if class of theList is list then
       repeat with i from 1 to count of theList
           if (theItem is (LI(i, theList))) or ((LI(i, theList)) begins with theItem) then
               set end of indexList to i -- Appends number to end of list.
           end if
       end repeat
   else if class of theList is text then -- Then theItem is also text.
       set {theLimit, x, i} to {count of theList, 1, 1}
       set theItem to (theItem as text)
       repeat while theLimit > (itemLength - 1)
           if theItem is (characters i thru (i + itemLength - 1) of theList as text) then
               set end of indexList to i
           end if
           set i to (i + 1)
           set theLimit to (theLimit - 1)
       end repeat
   end if
   if indexList is {} then return false
   --Else:
   return indexList
end getIndex



--This function is just for creating a short-hand way of accessing a list item.
--ItemNum can be a single integer, or a list of two integers for accessing a range of items:
on LI(itemNum, theList)
   if class of itemNum is integer then
       return (item itemNum of theList)
   else if class of itemNum is list then
       return (items (item 1 of itemNum as integer) thru ¬
           (item 2 of itemNum as integer) of theList)
   end if
end LI

--This function is for assigning a value to a list item:
on setLI(itemNum, theList, theValue)
   set item itemNum of theList to theValue
end setLI

-- This function separates pieces of a string into list items, using theDelimit
-- as the separator:
on explode(theString, theDelimit)
   set origDelimit to AppleScript's text item delimiters
   set AppleScript's text item delimiters to theDelimit
   set theResult to every text item of theString
   set AppleScript's text item delimiters to origDelimit
   return theResult
end explode

--This function re-assembles a list of strings into a single string,
--using theDelimit as glue to reconnect each string.
on implode(textList, theDelimit)
   set origDelimit to AppleScript's text item delimiters
   set AppleScript's text item delimiters to theDelimit
   set theString to (textList as string)
   set AppleScript's text item delimiters to origDelimit
   return theString
end implode


--We use this function to find a substring within a string that matches an item in a list.
--It returns 3 items: the position of the last character of the substring as a negative integer,
--and the 2nd item is total length of the substring. The 3rd item is the substring itself.
on findEndCharPosition(theString, beginPos, theList)
   set theList to item 1 of removeDuplicates(theList) --removes any duplicate items.
   set itm to character beginPos of theString
   set z to count of theString
   repeat with i from 1 to count of theList
       if LI(i, theList) begins with itm then
           if itm is LI(i, theList) then return {(beginPos + 1 - 2 - z), (count of itm), itm}
           set y to 1
           set itm to (characters beginPos thru (beginPos + y) of theString) as string
           repeat while LI(i, theList) begins with itm
               if itm is LI(i, theList) then
                   set subLength to (count of itm)
                   set lastLetterPosition to (beginPos + subLength - 2 - z)
                   return {lastLetterPosition, subLength, itm}
               end if
               set y to (y + 1)
               set itm to (characters beginPos thru (beginPos + y) of theString) as string
           end repeat
       end if
   end repeat
end findEndCharPosition

--Returns list of two items: first is modified version of lst with duplicates removed.
--Second item is list of indexes of removed items.
on removeDuplicates(lst)
   local lst, itemRef, res, itm
   try
       if lst's class is not list then error "not a list." number -1704
       script k
           property l : lst
           property res : {}
           property indx : {}
       end script
       repeat with i from 1 to count of k's l
           set itm to (item i of k's l)
           if k's res does not contain {itm} then
               set k's res's end to itm
           else
               set k's indx's end to i
           end if
       end repeat
       return {k's res, k's indx}
   on error eMsg number eNum
       return false
   end try
end removeDuplicates

Last edited by tootall8888 (2016-01-19 05:34:03 pm)

Offline

 
  • Index
  •  » Code Exchange
  •  » TextEdit Script to Find/Replace anything that is NOT the given string

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)