TextEdit & "set every word" weirdness...

hello all - newbie Applescripter here.

I’ve been working on a script that takes a template TextEdit document, and using info gathered from Address Book, creates a letter substituting in the info for known coding tags.

Anyway, I’ve run into problems with just one of the instances of code, and I was hoping somebody could help me figure out why.

Create a TextEdit document that looks like this:

Now, run the following script:


tell application "TextEdit"
	tell text of the front document
		set every word where it is "myFName" to "Ciaran"
		set every word where it is "myMName" to "P. A."
		set every word where it is "myLName" to "Connelly"
	end tell
end tell

After running the script, the expected result would be 7 lines that say “Ciaran P. A. Connelly” but instead I get the following:

So what’s going on? I assume the weirdness occurs because the searched for tag occurs more than once, and because after it is found, the word count for the document changes (since I have two middle initials). i.e. the “set every” command searches, finds that words 2, 5, 8, 11, 14, 17, 20 are the ones that should be changed into “P. A.” and then changes the words with that number, but after it changes the first one, it should look to change word 6 rather than word 5, since the “P. A.” bumped the number of every subsequent word up one. (After the next substitution it should be looking for word 10 rather than 8, since two extra words have been added, etc.)

Assuming that’s right, is there a way around this? I’m really just looking for a way to efficiently do several find and replaces via Applescript, and the changing word count gets in the way of all the different methods I’ve tried so far…

Any help is MUCH appreciated.

Thanks!

cpac

Hi,

I’m wasn’t sure if working with offsets work with TextEdit so did it this way:

property tag_list : {{“myFName”, “Ciaran”}, {“myMName”, “P. A.”}, {“myLName”, “Connelly”}}
tell application “TextEdit”
activate
repeat with this_tag in tag_list
set the_tag to item 1 of this_tag
set rstring to item 2 of this_tag
set word_count to (count words of rstring)
tell text of front document
if word_count is 1 then
set (every word whose it is the_tag) to rstring
else
set tag_count to count (every word whose it is the_tag)
repeat with i from tag_count to 1 by -1
set (word i of every word whose it is the_tag) to rstring
end repeat
end if
end tell
end repeat
end tell

Working with words can get tricky with special characters and you may run into bugs later.

EDIT: and BTW, when you use the ‘every element’ reference form, you get a threaded list in that statement. The script works on each element of the list seperately and not sequentially.

gl,

First of all - thanks a lot! Just a few follow-up questions:


property tag_list : {{"myFName", "Ciaran"}, {"myMName", "P. A."}, {"myLName", "Connelly"}}
tell application "TextEdit"
	activate
	repeat with this_tag in tag_list
		set the_tag to item 1 of this_tag
		set rstring to item 2 of this_tag
		set word_count to (count words of rstring)
		tell text of front document
			if word_count is 1 then
				set (every word whose it is the_tag) to rstring
			else
				set tag_count to count (every word whose it is the_tag)
				repeat with i from tag_count to 1 by -1
					set (word i of every word whose it is the_tag) to rstring
				end repeat
			end if
		end tell
	end repeat
end tell

(1) So basically, this fixes the problem by counting from the back of the document an replacing those instances where the data is more than one word - (changing a later word doesn’t affect the number of the words that came before) - right?

So, is there any reason to bother doing the if/else statement, rather than just using the repeat loop for everything (even single word substitutions?)

  • noted. I originally had all the tags surrounded by “<>” s but that broke things.

(2) I’m not sure exactly what this means (being a newbie) – could you elaborate a little? (Threaded list = list where each element is a ?)

Thanks again for all your help


cpac

Hi cpac,

First I would like to say that the example was just made for the perfect situation with the file open in TextEdit and the text exactly as you stated. You propbably know this but there should be error checking added.

(1)
You are correct about the execution of the script. Although, the length of the script doesn’t determine its speed. I did several quick tests which shows the speed difference. It uses Jon’s Commands scripting addition’s command ‘the ticks’:

http://www.seanet.com/~jonpugh/

Here’s the first with the if…then conditional:

property tag_list : {{“myFName”, “Ciaran”}, {“myMName”, “P. A.”}, {“myLName”, “Connelly”}}
tell application “TextEdit”
activate
set t1 to (the ticks)
repeat with this_tag in tag_list
set the_tag to item 1 of this_tag
set rstring to item 2 of this_tag
set word_count to (count words of rstring)
tell text of front document
if word_count is 1 then
set (every word whose it is the_tag) to rstring
else
set tag_count to count (every word whose it is the_tag)
repeat with i from tag_count to 1 by -1
set (word i of every word whose it is the_tag) to rstring
end repeat
end if
end tell
end repeat
set t2 to (the ticks)
end tell
set d to t2 - t1
activate
display dialog d

– 16, 10, 13, 14, 14 ticks

Here’s the second script using a repeat loop for every tag:

property tag_list : {{“myFName”, “Ciaran”}, {“myMName”, “P. A.”}, {“myLName”, “Connelly”}}
tell application “TextEdit”
activate
set t1 to (the ticks)
repeat with this_tag in tag_list
set the_tag to item 1 of this_tag
set rstring to item 2 of this_tag
tell text of front document
set tag_count to count (every word whose it is the_tag)
repeat with i from tag_count to 1 by -1
set (word i of every word whose it is the_tag) to rstring
end repeat
end tell
end repeat
set t2 to (the ticks)
end tell
set d to t2 - t1
activate
display dialog d

– 26, 25, 27, 27, 28 ticks

As you can see, it took about twice as long for the second script. There are probably other ways to decrease the speed, but it would be a long story.

About the “special” characters, there are other characters that separate words and some that are words in itself. I placed a list of these characters in a post once, but can’t remember what they were right now. I think one was the “-” sign etc.

(2)
The AppleScriptLanguageGuide says that the ‘every element’ reference form returns a list. This is partially true, but it’s not a list when you use it in the same statement. What I meant was that if you use a command mixed with this reference form, then it works on each element, but not the list as a whole in the sense of lists. What? Anyway, hard to explain. I call this list a multi threaded list (made this up). :slight_smile: I was trying to think of a good example of this and am working on it, but here’s a quicky using the Finder:

(a) command + every element

set desk_path to (path to desktop) as string
tell application “Finder”
activate
try
make new folder at desktop with properties {name:“My Folder”}
set folder_ref to result
on error
set folder_ref to folder (desk_path & “My Folder” & “:”)
end try
open folder_ref
repeat with i from 1 to 3
set file_name to (“File” & i)
make new file at folder_ref with properties {name:file_name}
end repeat
delay 1
set name_list to (name of every file of folder_ref)
end tell

(b) command + real list

set desk_path to (path to desktop) as string
tell application “Finder”
activate
try
make new folder at desktop with properties {name:“My Folder”}
set folder_ref to result
on error
set folder_ref to folder (desk_path & “My Folder” & “:”)
end try
open folder_ref
repeat with i from 1 to 3
set file_name to (“File” & i)
make new file at folder_ref with properties {name:file_name}
end repeat
delay 1
set file_list to every file of folder_ref
set name_list to (name of file_list)
end tell

This second example errors because you can’t get the name of a list. However, the previous script works because you’re getting the name of each file seperately and does not work on the list as a whole. Can you see how it works When used in the same statement? How do you like my “multi-threaded list” name for this type of list?

gl,

Hi,

It’s easier to see with the ‘get’ command:

(a)
set desk_path to (path to desktop) as string
tell application “Finder”
activate
try
make new folder at desktop with properties {name:“My Folder”}
set folder_ref to result
on error
set folder_ref to folder (desk_path & “My Folder” & “:”)
end try
open folder_ref
repeat with i from 1 to 3
set file_name to (“File” & i)
make new file at folder_ref with properties {name:file_name}
end repeat
delay 1
get name of (every file of folder_ref)
end tell

(b)
set desk_path to (path to desktop) as string
tell application “Finder”
activate
try
make new folder at desktop with properties {name:“My Folder”}
set folder_ref to result
on error
set folder_ref to folder (desk_path & “My Folder” & “:”)
end try
open folder_ref
repeat with i from 1 to 3
set file_name to (“File” & i)
make new file at folder_ref with properties {name:file_name}
end repeat
delay 1
set file_list to every file of folder_ref
get name of file_list
end tell

gl,