Search code examples
filetextreplacefindapplescript

Find and replace several instances in text files using AppleScript


I have absolutely no knowledge of coding or whatsoever. But on a daily routine I have to open a file in TextEdit for Mac to open a .txt file and find and replace several text instances. Not difficult, but it would be great to have an automated solution for this (saving time and avoiding human error).

Looking on this site, I've found this interesting script by dj bazzie wazzie, and with Automator even I can get it to work, so that's hopeful! 😉

set stringToFind to "replace that"
set stringToReplace to "with this"
set theFile to choose file
set theContent to read theFile as «class utf8»
set {oldTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, stringToFind}
set ti to every text item of theContent
set AppleScript's text item delimiters to stringToReplace
set newContent to ti as string
set AppleScript's text item delimiters to oldTID
try
    set fd to open for access theFile with write permission
    set eof of fd to 0
    write newContent to fd as «class utf8»
    close access fd
on error
    close access theFile
end try

However, I need to change not 1 but 3 things in the file. How can I adapt this code in a way that not "replace that" is replaced by "with this", but e.g. "unripe apple" by "ripe apple", "unripe kiwi" by "ripe kiwi" and "unripe banana" by "ripe banana"?

I've been puzzling on this, and probably the answer is way easier than expected, as I am quite a noob, I haven't managed to come to a solution.

Ideas on this are very welcome. Many thanks in advance!


Solution

  • The example AppleScript code, shown below, was tested in Script Editor under macOS Catalina with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1.

    • 1 Assumes necessary and appropriate setting in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.

    Example AppleScript code:

    set textToFindList to {"unripe apple", "unripe kiwi", "unripe banana"}
    set textToReplaceWithList to {"ripe apple", "ripe kiwi", "ripe banana"}
    
    if (length of textToFindList) is not equal to ¬
        (length of textToReplaceWithList) then return
    
    set theFile to choose file
    -- tell application "Finder" to duplicate file theFile with exact copy
    set theText to read theFile as «class utf8»
    
    repeat with i from 1 to length of textToFindList
        set theText to my findAndReplaceInText(theText, ¬
            item i of textToFindList, ¬
            item i of textToReplaceWithList)
    end repeat
    
    my writeToFile(theText, theFile, true)
    
    
    --  # Handlers #
    
    on findAndReplaceInText(theText, theSearchString, theReplacementString)
        --considering case
        set AppleScript's text item delimiters to theSearchString
        set theTextItems to every text item of theText
        set AppleScript's text item delimiters to theReplacementString
        set theText to theTextItems as string
        set AppleScript's text item delimiters to ""
        return theText
        --end considering
    end findAndReplaceInText
    
    on writeToFile(theText, theFile, overwriteExistingContent)
        try
            set theFile to theFile as string
            if theFile contains "/" then
                set theOpenedFile to open for access theFile with write permission
            else
                set theOpenedFile to open for access file theFile with write permission
            end if
            if overwriteExistingContent is true then set eof of theOpenedFile to 0
            write theText to theOpenedFile starting at eof
            close access theOpenedFile
            return true
        on error
            try
                close access file theFile
            end try
            return false
        end try
    end writeToFile
    

    Notes:

    The writeToFile(theText, theFile, overwriteExistingContent) handler is a slightly modified handler from: Reading and Writing Files

    The handler from the linked Apple support document was modified to handle both POSIX and HFS+ file paths.

    The findAndReplaceInText(theText, theSearchString, theReplacementString) handler if from Finding and Replacing Text in a String from: Manipulating Text

    If you need case sensitive find/replace then uncomment the --considering case and --end considering lines of code in the on findAndReplaceInText(theText, theSearchString, theReplacementString) handler.

    If you'd to automatically make a backup copy of the file, before editing it, then remove -- from in front of the following line of code_:

    tell application "Finder" to duplicate file theFile with exact copy
    

    Note: The example AppleScript code is just that and sans any included error handling does not contain any additional error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.