Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Multiple find and replace

How can I make an app, with Automator, Apple Script, or some developer tool that will let me find and replace multiple items within a single document.

Here is what I need in a nutshell:

I create on-demand content for a local cable television station. I have to create individual XML files for metadata for each episode. I have made a template of the XML file, with key words in the fields that need to change. There are about twenty of them. The rest of the XML file stays the same.

Right now, I have to do a find and replace for each keyword, one at a time. (BTW, I have to use either Dashcode or Text Edit for this...)

I would like to have some kind of form or multiple find and replace feature so I can type all of my FIND fields paired with all of my REPLACE fields, then press return and have the entire XML file update.

I hope this makes sense. Any help would be appreciated.

MacG5 1.8Dual - 2GB RAM, MacBook Pro 2.4 - 4GB RAM, Mac OS X (10.5.2), FCP Studio1+2, DVC Pro25+50, AJA I/oHD, Z1U, FibreJet, Dell 2407 & 3007

Posted on Jul 26, 2008 7:27 AM

Reply
Question marked as Best reply

Posted on Jul 26, 2008 2:01 PM

Using lists and find/replace isn't that great with Automator, and it's dialogs don't even allow multiple line entries. I have a few AppleScript handlers that do most of your requirements (the multiple item edit dialog doesn't use find/replace pairs, but can use the find item as an item to edit), so I assembled a few of them into a script that should get you started. The following script reads the chosen file, prompts for the find terms (place your terms in the list as needed), puts up a dialog to edit the selected terms, does a find/replace, and finally makes a new file on the desktop with the result in it:

<pre style="
font-family: Monaco, 'Courier New', Courier, monospace;
font-size: 10px;
margin: 0px;
padding: 5px;
border: 1px solid #000000;
width: 720px; height: 340px;
color: #000000;
background-color: #FFDDFF;
overflow: auto;"
title="this text can be pasted into the Script Editor">
-- search and replace multiple items

on run
set TheFIle to choose file -- the original text file
set TheFolder to (path to desktop) -- the folder for the output file
set TheName to (GetUniqueName for TheFIle from TheFolder) -- the name for the output file
set TheText to read TheFIle -- get the text to edit

set Originals to {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"} -- the terms that can be replaced
set Originals to (choose from list Originals default items Originals with prompt "Select the terms to replace:" with multiple selections allowed) -- the specific terms to replace

set Replacements to (EditItems of Originals with Title given Prompt:"Edit the following replacement terms:") -- the replacement terms

repeat with AnItem from 1 to count Originals
set TheText to (ReplaceText of TheText from (item AnItem of Originals) to (item AnItem of Replacements))
end repeat

try -- write a new output file
tell application "Finder" to make new file at TheFolder with properties {name:TheName}
set OpenFile to open for access (result as alias) with write permission
write TheText to OpenFile starting at eof
close access OpenFile
on error errmess
try
log errmess
close access OpenFile
end try
end try

end run


to GetUniqueName for SomeFile from SomeFolder
(*
check if SomeFile exists in SomeFolder, creating a new unique name if needed
parameters - SomeFile [mixed]: a source file path
SomeFolder [mixed]: a folder to check
returns [text]: a unique file name and extension
*)
set {Counter, Divider} to {"00", "_"}

-- get the name and extension
set {name:TheName, name extension:TheExtension} to info for file (SomeFile as text)
if TheExtension is missing value then set TheExtension to ""
set TheName to text 1 thru -((count TheExtension) + 2) of TheName

set NewName to TheName & "." & TheExtension
tell application "System Events" to tell (get name of files of folder (SomeFolder as text))
repeat while it contains NewName
set Counter to text 2 thru -1 of ((100 + Counter + 1) as text) -- leading zero
set NewName to TheName & Divider & Counter & "." & TheExtension
end repeat
end tell

return NewName
end GetUniqueName


to EditItems of SomeItems given Title:TheTitle, Prompt:ThePrompt
(*
displays a dialog for multiple item edit (note that a return is used between each edit item)
for each of the items in SomeItems, a line containing it's text is placed in the edit box
the number of items returned are padded or truncated to match the number of items in SomeItems
parameters - SomeItems [list]: a list of text items to edit
TheTitle [boolean/text]: use a default or the given dialog title
ThePrompt [boolean/text]: use a default or the given prompt text
returns [list]: a list of the edited items, or {} if error
*)
set {TheItems, TheInput, TheCount} to {{}, {}, (count SomeItems)}
if TheCount is less than 1 then return {} -- error

if ThePrompt is in {true, false} then -- "with" or "without" Prompt
if ThePrompt then
set ThePrompt to "Edit the following items:" & return -- default
else
set ThePrompt to ""
end if
else -- fix up the given prompt a little
set ThePrompt to ThePrompt & return
end if

if TheTitle is in {true, false} then if TheTitle then -- "with" or "without" Title
set TheTitle to "Multiple Edit Dialog" -- default
else
set TheTitle to ""
end if

set {TempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, return}
set {SomeItems, AppleScript's text item delimiters} to {SomeItems as text, TempTID}

set TheInput to paragraphs of text returned of (display dialog ThePrompt with title TheTitle default answer SomeItems)

repeat with AnItem from 1 to TheCount -- pad/truncate entered items
try
set the end of TheItems to (item AnItem of TheInput)
on error
set the end of TheItems to ""
end try
end repeat
return TheItems
end EditItems


to ReplaceText of SomeText from OldItem to NewItem
(*
replace all occurances of OldItem with NewItem
parameters - SomeText [text]: the text containing the item(s) to change
OldItem [text]: the item to be replaced
NewItem [text]: the item to replace with
returns [text]: the text with the item(s) replaced
*)
set SomeText to SomeText as Unicode text -- TID's are case insensitive with Unicode text
set {TempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, OldItem}
set {ItemList, AppleScript's text item delimiters} to {text items of SomeText, NewItem}
set {SomeText, AppleScript's text item delimiters} to {ItemList as text, TempTID}
return SomeText
end ReplaceText
</pre>

HTH
21 replies
Question marked as Best reply

Jul 26, 2008 2:01 PM in response to RedTruck

Using lists and find/replace isn't that great with Automator, and it's dialogs don't even allow multiple line entries. I have a few AppleScript handlers that do most of your requirements (the multiple item edit dialog doesn't use find/replace pairs, but can use the find item as an item to edit), so I assembled a few of them into a script that should get you started. The following script reads the chosen file, prompts for the find terms (place your terms in the list as needed), puts up a dialog to edit the selected terms, does a find/replace, and finally makes a new file on the desktop with the result in it:

<pre style="
font-family: Monaco, 'Courier New', Courier, monospace;
font-size: 10px;
margin: 0px;
padding: 5px;
border: 1px solid #000000;
width: 720px; height: 340px;
color: #000000;
background-color: #FFDDFF;
overflow: auto;"
title="this text can be pasted into the Script Editor">
-- search and replace multiple items

on run
set TheFIle to choose file -- the original text file
set TheFolder to (path to desktop) -- the folder for the output file
set TheName to (GetUniqueName for TheFIle from TheFolder) -- the name for the output file
set TheText to read TheFIle -- get the text to edit

set Originals to {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"} -- the terms that can be replaced
set Originals to (choose from list Originals default items Originals with prompt "Select the terms to replace:" with multiple selections allowed) -- the specific terms to replace

set Replacements to (EditItems of Originals with Title given Prompt:"Edit the following replacement terms:") -- the replacement terms

repeat with AnItem from 1 to count Originals
set TheText to (ReplaceText of TheText from (item AnItem of Originals) to (item AnItem of Replacements))
end repeat

try -- write a new output file
tell application "Finder" to make new file at TheFolder with properties {name:TheName}
set OpenFile to open for access (result as alias) with write permission
write TheText to OpenFile starting at eof
close access OpenFile
on error errmess
try
log errmess
close access OpenFile
end try
end try

end run


to GetUniqueName for SomeFile from SomeFolder
(*
check if SomeFile exists in SomeFolder, creating a new unique name if needed
parameters - SomeFile [mixed]: a source file path
SomeFolder [mixed]: a folder to check
returns [text]: a unique file name and extension
*)
set {Counter, Divider} to {"00", "_"}

-- get the name and extension
set {name:TheName, name extension:TheExtension} to info for file (SomeFile as text)
if TheExtension is missing value then set TheExtension to ""
set TheName to text 1 thru -((count TheExtension) + 2) of TheName

set NewName to TheName & "." & TheExtension
tell application "System Events" to tell (get name of files of folder (SomeFolder as text))
repeat while it contains NewName
set Counter to text 2 thru -1 of ((100 + Counter + 1) as text) -- leading zero
set NewName to TheName & Divider & Counter & "." & TheExtension
end repeat
end tell

return NewName
end GetUniqueName


to EditItems of SomeItems given Title:TheTitle, Prompt:ThePrompt
(*
displays a dialog for multiple item edit (note that a return is used between each edit item)
for each of the items in SomeItems, a line containing it's text is placed in the edit box
the number of items returned are padded or truncated to match the number of items in SomeItems
parameters - SomeItems [list]: a list of text items to edit
TheTitle [boolean/text]: use a default or the given dialog title
ThePrompt [boolean/text]: use a default or the given prompt text
returns [list]: a list of the edited items, or {} if error
*)
set {TheItems, TheInput, TheCount} to {{}, {}, (count SomeItems)}
if TheCount is less than 1 then return {} -- error

if ThePrompt is in {true, false} then -- "with" or "without" Prompt
if ThePrompt then
set ThePrompt to "Edit the following items:" & return -- default
else
set ThePrompt to ""
end if
else -- fix up the given prompt a little
set ThePrompt to ThePrompt & return
end if

if TheTitle is in {true, false} then if TheTitle then -- "with" or "without" Title
set TheTitle to "Multiple Edit Dialog" -- default
else
set TheTitle to ""
end if

set {TempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, return}
set {SomeItems, AppleScript's text item delimiters} to {SomeItems as text, TempTID}

set TheInput to paragraphs of text returned of (display dialog ThePrompt with title TheTitle default answer SomeItems)

repeat with AnItem from 1 to TheCount -- pad/truncate entered items
try
set the end of TheItems to (item AnItem of TheInput)
on error
set the end of TheItems to ""
end try
end repeat
return TheItems
end EditItems


to ReplaceText of SomeText from OldItem to NewItem
(*
replace all occurances of OldItem with NewItem
parameters - SomeText [text]: the text containing the item(s) to change
OldItem [text]: the item to be replaced
NewItem [text]: the item to replace with
returns [text]: the text with the item(s) replaced
*)
set SomeText to SomeText as Unicode text -- TID's are case insensitive with Unicode text
set {TempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, OldItem}
set {ItemList, AppleScript's text item delimiters} to {text items of SomeText, NewItem}
set {SomeText, AppleScript's text item delimiters} to {ItemList as text, TempTID}
return SomeText
end ReplaceText
</pre>

HTH

Jul 27, 2008 2:54 PM in response to red_menace

Holy cow, that was a lot of work! Thanks for your efforts. I will check it out on Tuesday at work and get back to you. I found a bunch of apps for the PC, but I don't want to add Parallels to this workflow, it'll only slow me down. But if what you did works you have no idea (or maybe you do...) how much time you saved me.

Thanks again.

Matt

Jul 27, 2008 4:02 PM in response to RedTruck

I wasn't that much work, since I already had the handlers in my library. Most of the time was spent testing to make sure it worked correctly. Just note that the edit dialog uses returns after each entry, so all you need to do is put in your search terms, then edit the items in the dialog. I also have an entry dialog which might have been a little easier in that the items needed are in the prompt, but the dialog is limited in size so all that will fit is about 15 entries. Let me know how it turns out or if it needs some tweaking.

Jul 29, 2008 5:25 PM in response to RedTruck

Glad it worked for you. There are a lot of AppleScript resources at MacScripter, but there isn't quite as much available for Automator for some reason (and most of that is aimed at developing actions) - there is some information (between the developer speak) from Apple's developer site:

http://developer.apple.com/macosx/automator.html
http://developer.apple.com/documentation/AppleApplications/Conceptual/AutomatorC oncepts/Automator.html

Jan 29, 2009 11:36 AM in response to RedTruck

Red Menace,

You helped me so much when you sent me that script. I was wondering if you could help me just one more time. (I have started to learn objective-c and cocoa by the way, thanks for the tip.) I have the script referencing a file with an XML extension, and it is case sensitive. When it outputs the file to the desktop the extension is lower case and I have to change it every time. Seeing as I make several hundred of these at a time, it takes a while to change the case. Is there a way to have it output the file with the extension all upper case? I tried to find the place/places in the file where I might change the code, but none of my attempts have worked. Would be much obliged.

Jan 29, 2009 12:29 PM in response to RedTruck

Hello again

The GetUniqueName handler is the only place that the extension for the new file is broken out, so you can use a case-changing handler on the variable TheExtension there. I'm posting a general-purpose handler that changes case - you can add a call to it in the GetUniqueName handler like so:

-- after the statement:
if TheExtension is missing value then set TheExtension to ""
-- add:
set TheExtension to (ChangeCase of TheExtension to "upper")

<pre style="
font-family: Monaco, 'Courier New', Courier, monospace;
font-size: 10px;
margin: 0px;
padding: 5px;
border: 1px solid #000000;
width: 720px;
color: #000000;
background-color: #FFEE80;
overflow: auto;"
title="this text can be pasted into the Script Editor">
to ChangeCase of SomeText to CaseType
(*
changes the case or capitalization of SomeText to the specified CaseType using Python
parameters - SomeText [text]: the text to change
CaseType [text]: the type of case desired:
"upper" = all uppercase text
"lower" = all lowercase text
"title" = uppercase character at start of each word, otherwise lowercase
"capitalize" = capitalize the first character of the text, otherwise lowercase
returns [text]: the changed text
*)

set SomeText to SomeText as text
if CaseType is not in {"upper", "lower", "title", "capitalize"} then return SomeText

return (do shell script "/usr/bin/python -c \"import sys; print unicode(sys.argv[1], 'utf8')." & CaseType & "().encode('utf8')\" " & quoted form of SomeText)
end ChangeCase
</pre>

Mar 22, 2009 12:22 PM in response to red_menace

I am trying to create a watch folder that uses your script to:

1. Have a folder that receives multiple xml files that run the script one by one.
2. then move the files to an output folder.
3. remove the original from the watch folder.

I tried modifying the set TheFIle to choose file -- the original text file to:

with multiple selections allowed

But that doesn't seem to work. I know i'm missing a step. Any help is much appreciated!

Thanks!

Mar 22, 2009 1:13 PM in response to gamebreakers

To handle multiple files you will need to repeat through each item in a list (for example, move the items in the run handler to a separate one and add statements to the folder action handler to repeat through the items sent to it). You shouldn't have to choose the file items with a dialog - the folder action will be providing them.

To help keep track of your specific modifications, it might be a good idea to post a new topic with your setup and what you have done so far.

May 15, 2014 7:16 AM in response to red_menace

Hi i know this is an old thread, but I'm looking to replace 3 items in an .xml file class utf-8


I've tried using red_menace's code but am having difficulty with getting it to work


what i need to achieve is two things

1) entering a variable "gNumber" and then adding that as a prefix to two terms "thumbs/" and "images/"

2) replacing "_blank" with "_self"


i don't need to create a unique file, just want to replace the original


---


on run

set theFile to choose file -- the original text file

set TheText to read theFile -- get the text to edit

set gNumber to text returned of (display dialog "What Gallery #?" default answer "")

set Originals to {"_blank", "images/", "thumbs/"} -- the terms that can be replaced

set Replacements to {"_self", gNumber & "images/", gNumber & "thumbs/"}

repeat with AnItem from 1 to count Originals

set TheText to (ReplaceText of TheText from (item AnItem of Originals) to (item AnItem of Replacements))

end repeat

try -- write a new output file

tell application "Finder" to make new file at TheFolder with properties {name:TheName}

set OpenFile to open for access (result as alias) with write permission

write TheText to OpenFile starting at eof

close access OpenFile

on error errmess

try

log errmess

close access OpenFile

end try

end try

end run



to EditItems of SomeItems given Title:TheTitle, Prompt:ThePrompt

(*

displays a dialog for multiple item edit (note that a return is used between each edit item)

for each of the items in SomeItems, a line containing it's text is placed in the edit box

the number of items returned are padded or truncated to match the number of items in SomeItems

parameters - SomeItems [list]: a list of text items to edit

TheTitle [boolean/text]: use a default or the given dialog title

ThePrompt [boolean/text]: use a default or the given prompt text

returns [list]: a list of the edited items, or {} if error

*)

set {TheItems, TheInput, TheCount} to {{}, {}, (count SomeItems)}

if TheCount is less than 1 then return {} -- error

if ThePrompt is in {true, false} then -- "with" or "without" Prompt

if ThePrompt then

set ThePrompt to "Edit the following items:" & return -- default

else

set ThePrompt to ""

end if

else -- fix up the given prompt a little

set ThePrompt to ThePrompt & return

end if

if TheTitle is in {true, false} then if TheTitle then -- "with" or "without" Title

set TheTitle to "Multiple Edit Dialog" -- default

else

set TheTitle to ""

end if

set {TempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, return}

set {SomeItems, AppleScript's text item delimiters} to {SomeItems as text, TempTID}

set TheInput to paragraphs of text returned of (display dialog ThePrompt with title TheTitle default answer SomeItems)

repeat with AnItem from 1 to TheCount -- pad/truncate entered items

try

set the end of TheItems to (item AnItem of TheInput)

on error

set the end of TheItems to ""

end try

end repeat

return TheItems

end EditItems



to ReplaceText of SomeText from OldItem to NewItem

(*

replace all occurances of OldItem with NewItem

parameters - SomeText [text]: the text containing the item(s) to change

OldItem [text]: the item to be replaced

NewItem [text]: the item to replace with

returns [text]: the text with the item(s) replaced

*)

set SomeText to SomeText as Unicode text -- TID's are case insensitive with Unicode text

set {TempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, OldItem}

set {ItemList, AppleScript's text item delimiters} to {text items of SomeText, NewItem}

set {SomeText, AppleScript's text item delimiters} to {ItemList as text, TempTID}

return SomeText

end ReplaceText

Multiple find and replace

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.