Pages: search and replace applescript

Hey all,

I was wondering if anyone had any tips or snippets for an applescript to take a Pages document and do a search and replace on a string of text. I’ve done it before in Word but i can’t find a “replace” command in the Pages dictionary.

Any ideas?

Thanks!!

This works for me:

-- Given a Pages doc with this content: "Now is the time for all good men to come to the aid of the party.

tell application "Pages"
	set toFind to "good"
	set toReplace to "bad"
	set theText to contents of document 1
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to toFind
	set textItems to theText's text items
	set AppleScript's text item delimiters to toReplace
	tell textItems to set editedText to beginning & toReplace & rest
	set AppleScript's text item delimiters to astid
	set text of document 1 to editedText
end tell

--> In Pages: "Now is the time for all bad men to come to the aid of the party."

Thanks!! That seems to work…only odd thing is if the search term doesn’t exist in the document it just puts the replacement string at the end of the document…

Hmm, actually upon playing around with it further, it seems that all the attributes in the document get overwritten with he attributes of the replaced string, so for instance if i have 14 point font at the top and a 11 point font paragraph below which contains a string to be replaced, the 14 point header ends up 11 point after the replace. Is there a way to maintain the original attributes?

I’d like to bring this back up, if I may (although I’m not the original poster, I have a similar question).

I have several rather lengthy documents, on which I need to perform a series of find-and-replace operations.

Basically, I need to convert each lowercase “s” in the document to a long “Å¿,” and then convert some of those back to short “s” based upon which characters are next to them (“s:,” “s-,” “sb,” “sk,” and “fs,” for instance).

Of course, long “Å¿” is a Unicode character, and the document is already formatted with text and paragraph styles, so I’d like to preserve those if possible. After having done a bit of research, it looks like I’ll need to script the UI directly, as Pages doesn’t include any Find & Replace entries in its dictionary.

Thoughts?

Thanks,

-Adam Johſon

Model: iMac
AppleScript: 2.0.1
Browser: Safari 525.27.1
Operating System: Mac OS X (10.5)

I don’t have pages and can’t find a copy of the scripting dictionary anywhere online. I would try something like this:

tell application "Pages"
	tell body text of document 1 to set CharRef to object reference of every character whose contents is "s"
	repeat with aRef in CharRef
		set contents of aRef to "Å¿,"
	end repeat
end tell

The reason that you are having the behavior that you were with the first method is that it is taking all the text out of the document, doing the search and replace in AppleScript, then putting it back in. This removes any local styling that you had. What you need to do is work on the text in the document so that it maintains the local styling.

You might be able to add in code like this:

if contents of character before aRef is "f" then
	--do something
else if character after aRef is ":"
	--do something else
else
	--do a third thing
end if

No guarantee this will work, but it is the direction that I would start with.

I can kind of see where you’re going with that, but it’s just plain not working. First, Applescript says it can’t get the body text of the document, and “contents” isn’t valid to use with “character” anyway. :confused:

Is there any way to script the UI directly? If so, that would be the easiest thing to do, I think.

I downloaded the demo from Apple and have a working script that you should be able to edit to fit your needs:

tell application "Pages"
	tell body text of document 1
		set offsetList to character offset of every character whose contents is "s"
		repeat with anOffset in offsetList
			if contents of character (anOffset + 1) is "f" then
				set character (anOffset) to "X"
			else if contents of character (anOffset + 1) is "a" then
				set character (anOffset) to "Y"
			else
				set character (anOffset) to "Z"
			end if
		end repeat
	end tell
end tell

Some explanation:

Body Text is a property of the document which holds the main text. This works directly on the this property.

It gets a list of offsets for every character that matches “s”. Things to note here you have to have contents, content errors out for me. When I posted before I was trying to get an object reference to the individual characters which works in other applications I have scripted but not in pages. The offset value works fine though and makes it easy to do the math for testing the character before and after.

When setting the character don’t use the contents, just set it as shown above.

There are two other areas that may appear on you’re page, a header and footer. This will not work on those, you would need to address those separately.

To handle the header and footer it looks like you need to get the reference for the page for the header or footer. This is because the header property is read only and not what you want to make the calls to. This holds a reference to “even header” or “odd header” depending if the page is odd or even. So to change them you need something similar to the following:

tell application "Pages"
	set footerRef to footer of page 1 of document 1
	tell footerRef
		set contents to "YYY"
	end tell
end tell

You can script the UI if needed, search the forum for examples. It is generally accepted that you script the UI as a last result though.

Thanks a bunch!

I made a few edits and got the Å¿cript below.

The only two iÅ¿Å¿ues now are (1) that on long documents, AppleÅ¿cript times out when Å¿etting offsetList to character offset of every character whose contents is “s,” and (2) it’s changing capital S characters to “s.”

Is there any way to change the timeout to something reasonable (like 2 or 3 minutes) and make it caſe ſenſitive?

Thanks!

-AJBlue98

tell application "Pages"
	tell body text of document 1
		set offsetList to character offset of every character whose contents is "s"
		repeat with anOffset in offsetList
			if contents of character (anOffset - 1) is "f" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "f" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "b" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "k" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is " " then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "." then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "," then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "/" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "?" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "!" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "~" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "-" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "“" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "”" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "'" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "\"" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "'" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is """ then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "*" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is ")" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "}" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "]" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is ":" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is ";" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is ">" then
				set character (anOffset) to "s"
			else if contents of character (anOffset + 1) is "\\" then
				set character (anOffset) to "s"
			else
				set character (anOffset) to "Å¿"
			end if
		end repeat
	end tell
end tell

To shorten it, hopefully speed it up a bit, and solve the case problem you were having:

set exceptionList to {"f", "b", "k", " ", ".", ",", "/", "?", "!", "~", "-", "“", "”", "'", "\"", "'", """, "*", ")", "}", "]", ":", ";", ">", "\\"}

tell application "Pages"
	activate
	with timeout of 300 seconds --5 minutes
		tell body text of document 1
			set offsetList to character offset of every character whose contents is "s"
			repeat with anOffset in offsetList
				if contents of character (anOffset - 1) is not "f" and contents of character (anOffset + 1) is not in exceptionList then
					set character (anOffset) to "Å¿"
				end if
			end repeat
		end tell
	end timeout
end tell

The main difference here is we are replacing the character only if it meets the condition. The condition is checking the characters before and after, with the after using an exception list. The timeout statement should element the problems that you are having with long documents.

That’s awesome–it’s way faster, too–but still not case sensitive. Capital “S” should never be converted to lowercase.

Any clues on this one?

Thanks,

-AJBlue98

Since Pages seems to be ignoring case and does not understand the considering statement built into AppleScript I put it a test for case using the ascii number. This will probably slow it down a bit since it adds another call to the program but should eliminate it changing capital “S”

set exceptionList to {"f", "b", "k", " ", ".", ",", "/", "?", "!", "~", "-", "“", "”", "'", "\"", "'", """, "*", ")", "}", "]", ":", ";", ">", "\\"}

tell application "Pages"
	activate
	with timeout of 300 seconds --5 minutes
		tell body text of document 1
			considering case
				set offsetList to character offset of every character whose contents is "s"
			end considering
			repeat with anOffset in offsetList
				if contents of character (anOffset - 1) is not "f" and contents of character (anOffset + 1) is not in exceptionList then
					set theCharacter to character (anOffset)
					if (ASCII number of theCharacter) is 115 then set character (anOffset) to "Å¿" --lowercase "s" = ascii number 115
				end if
			end repeat
		end tell
	end timeout
end tell

Thanks, Jerome! That nailed it! (Oh, and the ſpeed difference is negligible at worſt)! :smiley:

Okay, well that almoÅ¿t nailed it…

I was running this Å¿cript on the US ConÅ¿titution, and I realized that we never allowed for linefeeds, carriage returns, &c., Å¿o I did Å¿ome digging in the AppleScript documentation, and came up with the following (the applescript tags make the text show incorrectly, so I’ve omitted them here:

(*
This ſcript changes 20th Century-ſtyle type to 1776-era ſtandards with regards to the uſe of long "ſ."

Written by Jerome at MacScripter with input from AJBlue98.
http://macscripter.net/viewtopic.php?id=23896
*)

set exceptionList to {"f", "b", "k", " ", ".", ",", "/", "?", "!", "~", "-", "“", "”", "'", "\"", "'", """, "*", ")", "}", "]", ":", ";", ">", "\\", "\t", "\r", "\n"}

tell application "Pages"
	activate
	with timeout of 300 seconds --5 minutes
		tell body text of document 1
			set offsetList to character offset of every character whose contents is "s"
			repeat with anOffset in offsetList
				if contents of character (anOffset - 1) is not "f" and contents of character (anOffset + 1) is not in exceptionList then
					set theCharacter to character (anOffset)
					if (ASCII number of theCharacter) is 115 then set character (anOffset) to "Å¿" --lowercase "s" = ascii number 115
				end if
			end repeat
		end tell
	end timeout
end tell

Hello
I apologizes but when I run the script, I get:

tell application “Pages”
get character offset of every character of body text of document 1 whose contents = “s”
“Erreur dans Pages09 : NSReceiverEvaluationScriptError: 3”

I wanted to test this variant:


set exceptionList to {"f", "b", "k", " ", ".", ",", "/", "?", "!", "~", "-", "“", "”", "'", "\"", "'", """, "*", ")", "}", "]", ":", ";", ">", "\\", "	", "
", "
"}

tell application "Pages"
	activate
	with timeout of 300 seconds --5 minutes
		tell body text of document 1
			set offsetList to character offset of every character whose contents is "s"
			repeat with anOffset in offsetList
				if contents of character (anOffset - 1) is not "f" and contents of character (anOffset + 1) is not in exceptionList then
					if my isitAlowercases(character (anOffset)) then set character (anOffset) to "?" --lowercase "s" = ascii number 115
				end if
			end repeat
		end tell
	end timeout
end tell

on isitAlowercases(c)
	considering case
		set flag to c = "s"
	end considering
	return flag
end isitAlowercases

Alas, even this bare one:

tell application "Pages"
	activate
	with timeout of 300 seconds --5 minutes
		tell body text of document 1
			set offsetList to character offset of every character whose contents is "s"
			
		end tell
	end timeout
end tell

fails (I’m running Pages '09 under 10.4.11)

Yvan KOENIG (from FRANCE mardi 3 février 2009 22:36:46)

Hmm, I can tell you that the Å¿cript I poÅ¿ted works perfectly, but I’m uÅ¿ing Pages 08.

Hmm

I will retry tomorrow.

At this time, here, it fails the same with Pages '08.

Yvan KOENIG (from FRANCE mardi 3 février 2009 23:23:01)

Yvan,

I have the Pages 09 trial, US version with OS X 10.5.6, and your code seems to work fine for me. Your character replacements don’t make much sense to me but I assume that you are not doing this for English consumption. Doing a quick search I found these:

http://www.versiontracker.com/php/feedback/article.php?story=2005122814402962

http://macscripter.net/viewtopic.php?id=19120

There are some others as well if you google the error code. You also might try changing the tell blocks to look like this:

tell application "Pages"
   activate
   with timeout of 300 seconds --5 minutes
       tell document 1
             tell body text
                 set offsetList to character offset of every character whose contents is "s"
       end tell
   end timeout
end tell

I continue to get the same behaviour with

Pages '08 French on 10.4.11
Pages '08 EnglishUS on 10.4.11
Pages '09 French on 10.4.11
Pages '09 EnglishUS on 10.4.11

The problem behaves with the bare script:

tell application "Pages"
	activate
	with timeout of 300 seconds --5 minutes
		tell document 1
			tell body text
				set offsetList to character offset of every character whose contents is "s"
			end tell
		end tell
	end timeout
end tell

I will continue to test running the operating system in English.

About the character replacement, it’s not my problem but the one of the original poster.
I’m just interested by the bare code.

Yvan KOENIG (from FRANCE mercredi 4 février 2009 10:32:50)

I made complementary tests.

Refuse to work in every version/langauge under 10.4.11

Behaves flawlessly under 10.5.6.

I will sent a report to Apple.

(*
This script changes 20th Century-style type to 1776-era standards with regards to the use of long "?."

Written by Jerome at MacScripter with input from AJBlue98.
http://macscripter.net/viewtopic.php?id=23896
*)

set exceptionList to {"f", "b", "k", " ", ".", ",", "/", "?", "!", "~", "-", "“", "”", "'", "\"", "'", """, "*", ")", "}", "]", ":", ";", ">", "\\", "	", "
", "
"}

tell application "Pages"
	activate
	with timeout of 300 seconds --5 minutes
		tell body text of document 1
			set offsetList to character offset of every character whose contents is "s"
			repeat with anOffset in offsetList
				if contents of character (anOffset - 1) is not "f" and contents of character (anOffset + 1) is not in exceptionList then
					if my isItAlowercases(character (anOffset)) then set character (anOffset) to "?"
				end if
			end repeat
		end tell
	end timeout
end tell

on isItAlowercases(c)
	local flag
	considering case
		set flag to c = "s"
	end considering
	return flag
end isItAlowercases

Yvan KOENIG (from FRANCE mercredi 4 février 2009 11:57:06)