Question on Applescript code...

Hi, I know very little applescript but pieced together a group of clips to be able to do something rather simple that I can do at the command line or with BBEdit regarding text find and replace in a group of files.

I am trying to create a drag and drop app that will allow me to drop a folder full of files on it, parse throught them, examine the text files and replace XXX with YYY in them. I want to do this without calling another app like BBEdit, just do this with Applescript. This is for someone that I know and I need it simple and easy. I don’t want to use another find and replace program, just a drag and drop to replace an already fixed text with another. I think this can be done. Here is what I have so far…


-- the list of file types which will be processed
-- eg: {"PICT", "JPEG", "TIFF", "GIFf"}
property type_list : {"TEXT", "HTML"}
-- since file types are optional in Mac OS X,
-- check the name extension if there is no file type
-- NOTE: do not use periods (.) with the items in the name extensions list
-- eg: {"txt", "text", "jpg", "jpeg"}, NOT: {".txt", ".text", ".jpg", ".jpeg"}
property extension_list : {"htm", "html", "xml"}

-- This droplet processes both files or folders of files dropped onto the applet
on open these_items
	repeat with i from 1 to the count of these_items
		set this_item to (item i of these_items)
		set the item_info to info for this_item
		if folder of the item_info is true then
			process_folder(this_item)
		else if (alias of the item_info is false) and ¬
			((the file type of the item_info is in the type_list) or ¬
				the name extension of the item_info is in the extension_list) then
			process_item(this_item)
		end if
	end repeat
end open

-- this sub-routine processes folders
on process_folder(this_folder)
	set these_items to list folder this_folder without invisibles
	repeat with i from 1 to the count of these_items
		set this_item to alias ((this_folder as text) & (item i of these_items))
		set the item_info to info for this_item
		if folder of the item_info is true then
			process_folder(this_item)
		else if (alias of the item_info is false) and ¬
			((the file type of the item_info is in the type_list) or ¬
				the name extension of the item_info is in the extension_list) then
			process_item(this_item)
		end if
	end repeat
end process_folder

-- this sub-routine processes files
on process_item(this_item)
	-- NOTE that the variable this_item is a file reference in alias format
	-- FILE PROCESSING STATEMENTS GOES HERE
	set theText to "XXX"
	set ReplaceString to "YYY"
	
	set OldDelims to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "XXX"
	set newText to text items of theText
	set AppleScript's text item delimiters to ReplaceString
	set finalText to newText as text
	set AppleScript's text item delimiters to OldDelims
	finalText
end process_item


Any ideas of where things are going wrong? I think the find and replace sub-string at the bottom doesn’t look right… It seems so simple a task, but…

Thanks.

-Adam

[Edited for Code]

Here, a powerfull search/replace routine:

on SR(s, r, theText)
    tell (a reference to AppleScript's text item delimiters)
        set {oldTID, contents} to {contents, {s}}
        try
           set {lT, contents} to {(text items of theText), {r}}
            set {nT, contents} to {(lT as text), oldTID}
            return nT
       on error msg number n
           set contents to oldTID
           error msg number n
       end try
   end tell
end SR

More Basically:

set input_text to "Today is sunday"
set search_for_text to "sunday"
set replacement_text to "monday"

set applescript's text item delimiters to search_for_text
set input_text to input_text's text items
set applescript's text item delimiters to replacement_text
set output_text to input_text as text
set applescript's text item delimiters to {""}
output_text --> "Today is monday"

About your s/r routine, I can’t see nowhere the string you’re looking for… Or, if you’re looking for “XXX”, you’re not providing a text where “XXX” can be found…

Using AppleScript’s Text Item delimiters is a novel idea for your script.

However, and I don’t know if this is just your debugging code, you don’t actually do anything with the files - your pass a file into ProcessFile(), but never reference it. The code will work if you:

set theText to read (this_item)

I’ll assume that’s just your debugging code. :slight_smile:

Additionally, if you want to make your changes permanent, you’ll need to save the changes back to disk. In this case:

open for access this_item with write permission
write finalText to this_item starting at 0
close this_item

Thank you both for your help.

Camelot, I added your suggestions, many thanks. Using the text delimiters actually came from Apple’s applescript site.

The script works well now, but there is 1 small problem.

The replace of the text XXX with YYY works, but it won’t insert the text just replace the characters. This is only evidend when XXX and YYY are different string lengths.

For example if I want to replace XXX with YYYQQQ:

“XXXSomething” becomes “YYYQQQething” instead of “YYYQQQSomething”

Any ideas are most appreciated.

Here is the code I am using:


-- the list of file types which will be processed
-- eg: {"PICT", "JPEG", "TIFF", "GIFf"}
property type_list : {"TEXT", "HTML"}
-- since file types are optional in Mac OS X,
-- check the name extension if there is no file type
-- NOTE: do not use periods (.) with the items in the name extensions list
-- eg: {"txt", "text", "jpg", "jpeg"}, NOT: {".txt", ".text", ".jpg", ".jpeg"}
property extension_list : {"htm", "html", "xml"}

-- This droplet processes both files or folders of files dropped onto the applet
on open these_items
	repeat with i from 1 to the count of these_items
		set this_item to (item i of these_items)
		set the item_info to info for this_item
		if folder of the item_info is true then
			process_folder(this_item)
		else if (alias of the item_info is false) and ¬
			((the file type of the item_info is in the type_list) or ¬
				the name extension of the item_info is in the extension_list) then
			process_item(this_item)
		end if
	end repeat
end open

-- this sub-routine processes folders
on process_folder(this_folder)
	set these_items to list folder this_folder without invisibles
	repeat with i from 1 to the count of these_items
		set this_item to alias ((this_folder as text) & (item i of these_items))
		set the item_info to info for this_item
		if folder of the item_info is true then
			process_folder(this_item)
		else if (alias of the item_info is false) and ¬
			((the file type of the item_info is in the type_list) or ¬
				the name extension of the item_info is in the extension_list) then
			process_item(this_item)
		end if
	end repeat
end process_folder

-- this sub-routine processes files
on process_item(this_item)
	-- NOTE that the variable this_item is a file reference in alias format
	-- FILE PROCESSING STATEMENTS GOES HERE
	open for access this_item with write permission
	set theText to read (this_item)
	set theText to "XXX"
	set ReplaceString to "YYYQQQ"
	
	set OldDelims to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "XXX"
	set newText to text items of theText
	set AppleScript's text item delimiters to ReplaceString
	set finalText to newText as text
	set AppleScript's text item delimiters to OldDelims
	finalText
	write finalText to this_item starting at 0
end process_item
close this_item

I assume that it has something to do with the write finalText line.

Thanks.
-Adam

JJ, your code works nicely in the script as well (is it better? faster?)

It also has the same problem of not doing the insert where the text is.

Thanks for any further help you can give.

-Adam

Let’s assume that theText is text read from the file. So, you must not overwrite its contents later with a set theText to “XXX”.
Instead of this, you must set up a “I’m searching this text”: set Looking_For_This to “XXX”:

set file_ref to open for access this_item with write permission
set Entire_Text to (read file_ref)
set Looking_For to "XXX"
set Replace_With to "YYYQQQ"

--> start process
set applescript's text item delimiters to Looking_For
set Entire_Text to Entire_Text's text  items
--> deleted every ocurrence of "XXX" in Entire_Text
--> here you get a list of rest of items
set applescript's text item delimiters to Replace_With
set Entire_Text to Entire_Text as text
--> You insert the replacement string in place of old "XXX" ocurrences"
set applescript's text item delimiters to {""}
--> reset TIDs

Now, you have OK your finaltext (called here “Entire_Text”). Finish process:

set eof of file_ref to 0
--> delete contents of the file, to start writing the new ones
write Entire_Text to file_ref
--> write the new text
close access file_ref
--> end!

To understand how does it work this search/replace routine, you must look to the partial results:

set theText to "Hello, Dolly"
set Looking_For to "Dolly"
set Replace_With to "Mary"

You need as output “Hello, Mary”, ok?

set applescript's text item delimiters to Looking_For
set theText to text items of theText
--> {"Hello, ", ""} --> A list of two items, where you cut with "Dolly"--> "Hello, " and the last text item: ""

set applescript's text item delimiters to Replace_With
set theText to theText as text
--> coerce that two-item list to text. Between these two items you place the new delimiters "Mary"
--> "Hello, " + delimiter + "" = "Hello, Mary"

set applescript's text item delimiters to {""}
--> reset TIDs to its original value: a single empty item list.

You could also download Satimage.osax that has text replacement in its features.