1

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!

2 Answers2

0

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.

user3439894
  • 7,266
  • 3
  • 17
  • 28
  • Hi user3439894, Thank you for your quick response! I have tested your script, and it works, so I am more grateful than I can express! Only one thing I need to know to use it in practice. One of the replacements I have to do, is replacing an HTML URLs. It seems that the script doesn’t like signs such as “ or / . How can I make this work for URLs and texts with special characters such as changing a Visit Stack Overflow to Visit something different (not partially but as a whole)? – vegan_enchilada May 03 '21 at 20:29
  • @vegan_enchilada, The _examples_ you gave in your OP was of **plain text** in a _text file_, not **HTML** (**HyperText Markup Language**) and as such is outside the scope of the original question you asked. You should post another question with proper examples of before and after, etc. Please have a look at [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) and [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask). **HTML** while being _text_ is not considered a _text file_ for the purpose of parsing it. – user3439894 May 03 '21 at 20:56
  • Hi user3439894. You're absolutely right. I hadn't thought this well through. However, changing the URL and the URL text works like a charm. Many thanks! – vegan_enchilada May 03 '21 at 21:42
  • @vegan_enchilada, Are you set on how to use the _example_ **AppleScript** _code_ or do you need some additional help with that? – user3439894 May 03 '21 at 22:24
  • Hi user3439894, I know how to use this AppleScript. Thank you for your help. – vegan_enchilada May 04 '21 at 20:30
0

Here is a different AppleScript solution which should give you the same results that you were looking for. It will replace every instance of “unripe” with “ripe”, in your chosen file and apply and save those changes directly to your file.

I added a little “fail-safe” and created a back up of the original file, with the added file extension “bak” (in case you screw up and all hell breaks loose and you need to revert back).

The g option I added at the end stand for “global” (the text replacement happens throughout the document rather than only the first instance).

Just be sure to have an equal number of items in both textToReplace and replacementText properties.

property textToReplace : {"unripe", "word2", "moore text", "<a href=\"stackoverflow.com\">Visit Stack Overflow</a>", "delete this phrase"}
property replacementText : {"ripe", "Word Two", "More Text", "<a href=\"anyurl.com\">Visit something different</a>", ""}

activate
set theFile to quoted form of POSIX path of (choose file)
do shell script "cp " & theFile & " " & theFile & ".bak"

repeat with i from 1 to count of textToReplace
    do shell script "sed -i '' 's|" & (item i of textToReplace) & ¬
        "|" & (item i of replacementText) & "|g' " & theFile
end repeat

Here is a “Before & After” screenshot of the original text and then the text after the replacements. enter image description here

wch1zpink
  • 3,026
  • 1
  • 8
  • 19
  • RE: "It will replace every instance of “unripe” with “ripe”," -- I have to say that I seriously doubt that the actual _word_ the OP want to replace is _unripe_ with _ripe_. I believe the _examples_ where just _place holders_ for the actual _word(s)_ and or _phase(s)_ and that in reality there is more than one _word(s)_ and or _phase(s)_, and they are distinctly different. If that is the case, then the `sed` _command_ as currently written doesn't cover multiple distinctly different _word(s)_ and or _phase(s)_. – user3439894 May 05 '21 at 19:47
  • I believe the edits I have made will address the issues you have pointed out. – wch1zpink May 06 '21 at 02:51