Pages: System Events Scripting for Search & Replace

Well, instructing Pages to conditionally format paragraph styles via AS really was a pain. AS slowed down as it’s a 102 page document. Iterating through the paragraphs was just too long.

So, I want to SE the find/replace window and go that route.

Can anybody point me in the right direction? I want to use the find/replace window though System Events, but I can’t get into the Advanced pane of the Find window. Also not sure how to set search parameters (including paragraph style) in that window when I get to it.

Any help appreciated.

Cheers

It seems that this one without GUI Scripting is reasonably fast.


tell application "Pages" to tell document 1
(*
I don't know the English names of the predefined styles so I use the French ones. *)
	set style_1 to paragraph style "Sous-section 2"
	set style_2 to paragraph style "Sous-section 1"
	set les_styles to paragraph style of every paragraph
	set i to 1
	repeat with un_style in les_styles
		if contents of un_style is style_1 then set paragraph style of paragraph i to style_2
		set i to i + 1
	end repeat
end tell -- Pages

Yvan KOENIG (VALLAURIS, France) vendredi 1 juillet 2011 16:09:30

Salut Yvan.

You are only changing styles. I am starting with a file that has no styles. I’m trying to find a way to AppleScript through the Find/Replace window of Pages v4, by going through the Advanced Panel.

Cheers

Given your original post I assumed that it was a style. As it’s not that, It would be useful to know what would be the key to search.

Yvan KOENIG (VALLAURIS, France) vendredi 1 juillet 2011 17:15:53

Well, I was asking about System Events in order to use the search window, but I’ll answer your question.

I want to search for “#####” and replace that with a paragraph style of “Section”
Then replace “#####” with “”

I then want to search for “####” and replace that with a paragraph style of “Class”
Then replace “####” with “”

I then want to search for “###” and replace that with a paragraph style of “Fee”
Then replace “###” with “”

That way my marked-up text turns into a proper pages file with no markers.

Here is a plain Vanilla script doing the trick.
I kept the original structure which treated several documents.


--[search_apply_styles]
(*
Enregistrer le script en tant que script : search_apply_styles.scpt
déplacer l'application créée dans le dossier
<VolumeDeDémarrage>:Users:<votreCompte>:Library:Scripts:Applications:Pages:
Il vous faudra peut-être créer le dossier Pages et peut-être même le dossier Applications.

Ouvrir au premier plan le document Pages à traiter.
menu Scripts > Pages > search_apply_styles
Le script applique les styles définis par les prperties name_os_styleX
aux paragraphes contenant les balises et supprime celles_ci.

--=====

L'aide du Finder explique:
L'Utilitaire AppleScript permet d'activer le Menu des scripts :
Ouvrez l'Utilitaire AppleScript situé dans le dossier Applications/AppleScript.
Cochez la case "Afficher le menu des scripts dans la barre de menus".

--==========

Save the script as a Script : search_apply_styles.scpt

Move the newly created application into the folder:
<startup Volume>:Users:<yourAccount>:Library:Scripts:Applications:Pages:
Maybe you would have to create the folder Pages and even the folder Applications by yourself.
Open the Pages document to treat at front.
menu Scripts > Pages > search_apply_styles
The script apply the styles defined by the properties name_of_styleX
to paragraphs embedding the predefined balises and remove these ones.

--=====

The Finder's Help explains:
To make the Script menu appear:
Open the AppleScript utility located in Applications/AppleScript.
Select the "Show Script Menu in menu bar" checkbox.

--==========

Yvan KOENIG (Vallauris, FRANCE)
2011/07/01
*)
--=====

(*
Edit these three properties to fit your needs
*)
property name_of_style1 : "Titre"
property name_of_style2 : "Sous-section 1"
property name_of_style3 : "Sous-section 2"

property theApp : "Pages"
property pieces : {}
property listeOffsets : {}

--=====

on run
	local d_name
	my nettoie()
	
	tell application "Pages" to tell document 1
		set d_name to name
	end tell
	my apply_the_styles(d_name)
	
	--tell application "Pages" to close document d_name saving yes
	
	my nettoie()
	
end run

--=====

on nettoie()
	set searched to missing value
	set replacement to missing value
	set my pieces to {}
	set my listeOffsets to {}
end nettoie

--===

on apply_the_styles(dName)
	local tb, the_style1, the_style2, the_style3, searched, cs, i, ofi
	tell application "Pages" to tell document dName
		set tb to body text
		set the_style1 to paragraph style name_of_style1
		set the_style2 to paragraph style name_of_style2
		set the_style3 to paragraph style name_of_style3
	end tell
	set searched to "###"
	set cs to count of searched
	if tb contains searched then
		set my pieces to my decoupe(tb, searched)
		(* builds a list of offsets of the 'old text' in the body text *)
		repeat with i from 1 to ((count of my pieces) - 1)
			if i = 1 then
				set my listeOffsets to {1 + (count of item 1 of my pieces)}
			else
				copy (item (i - 1) of my listeOffsets) + cs + (count of item i of my pieces) to end of my listeOffsets
			end if
		end repeat
		
		tell application "Pages"
			with timeout of 300 seconds --5 minutes
				tell document 1
					repeat with i from (count of my listeOffsets) to 1 by -1
						(* apply the replacement *)
						set ofi to item i of my listeOffsets
						if character (ofi + cs) = "#" then
							if character (ofi + cs + 1) = "#" then -- #####
								set paragraph style of character ofi to the_style1
								select (characters ofi thru (ofi + cs + 2 - 1))
							else -- ####
								set paragraph style of character ofi to the_style2
								select (characters ofi thru (ofi + cs + 1 - 1))
							end if
						else -- ###
							set paragraph style of character ofi to the_style3
							select (characters ofi thru (ofi + cs - 1))
						end if
						set selection to ""
					end repeat
				end tell -- document
			end timeout
		end tell -- application
	end if -- tb contains
end apply_the_styles

--=====

on decoupe(t, d)
	local l
	set AppleScript's text item delimiters to d
	set l to text items of t
	set AppleScript's text item delimiters to ""
	return l
end decoupe

--=====

Yvan KOENIG (VALLAURIS, France) vendredi 1 juillet 2011 22:24:41

Yvan, wow. That works! Well done.

It takes up towards 30 minutes to handle the 100 pages of text, but it works.

Some questions:

  1. why go from the bottom to the top?

  2. Can you explain Text Item Delimiters?

Trying to figure out what you did here. Something tells me you aren’t looking at paragraphs and checking for a contains. I’d love to see how you approached this.

Cheers

Here’s a script that’s a trifle faster. It works from the end because it’s usually faster to do so. One possible reason for this is that when characters are removed from text in an application document, the end of the text and all its styling has to be moved up to fill the gap. Working from the end means that the text being moved up has itself had text removed from it, so there’s less to move overall. Another possible factor is that to indentify a point in the document text, the application has count from the beginning every time. If it has to count through text which it’s only just edited and may not have tidied up yet internally, it’s either got to sort that out before continuing or work its way through the stored pieces. (This is just happy Saturday-afternoon theorising. Don’t take it as an assertion of fact! But working from the end is certainly faster here.)

property styleKeys : {{"#####", "Section"}, {"####", "Class"}, {"###", "Fee"}} -- NB. Style markers arranged longest to shortest.

on stylise()
	tell application "Pages"
		tell document 1
			set paragraphTexts to paragraphs of body text
			repeat with p from (count paragraphTexts) to 1 by -1
				set paraText to item p of paragraphTexts
				repeat with k from 1 to (count styleKeys)
					set {marker, styleName} to item k of styleKeys
					if (paraText begins with marker) then
						set paragraph p of body text to text ((count marker) + 1) thru -1 of paraText
						set paragraph style of paragraph p of body text to paragraph style styleName
						exit repeat
					end if
				end repeat
			end repeat
		end tell
	end tell
end stylise

stylise()

(1) It seems that Nigel found a better approach.

(2) As I thought that there are less paragraphs to stylize than others, I decided to use the short marker “###” to split the body text in chunks.
To do that, the tool of choice are text item delimiters. As my English is far from perfect, I will not explain these objects.
Download AppleScript User Guide. You will get a description in plain English :slight_smile:
http://developer.apple.com/library/mac/documentation/AppleScript/Conceptual/AppleScriptLangGuide/AppleScriptLanguageGuide.pdf

Once I got the chunks, I checked if there were one or two characters # at the beginning of a character to decide which style needed to be applied and of course, I removed the characters #.

(3) Of course, Nigel and me, we scanned the document starting from the end.
For me, it was a basic requirement as I worked using the indexes of characters in the body text.
For Nigel scheme, I guess that it’s a property of the scheme used by the app to retrieve a descriptor.
It resemble to what we may see when we try to select a large block of text in a WP window.
It’s faster to start from the end of the block and move to the top than starting from the beginning and moving to the bottom.

(4) Now it’s time for me to study carefully the Nigel’s script.

Yvan KOENIG (VALLAURIS, France) samedi 2 juillet 2011 17:16:22

Hi guys. Nigel, thanks for the addition.

Yes, Yvan, the notation that I was using to decipher which style that should be applied, is indeed at the beginning of a paragraph. I guess I should have explained that these are all paragraph styles and the syntax would be at the beginning of the paragraph:

#####Section 55 blah blah blah
####Class 5507 Dog Bark
###Fee $15.00
Notes notes notes notes…
#####Section 56 blah blah blah
####Class 5601 Bake Pie
###Fee $18.00
Notes notes notes notes…

I originally tried to get all paragraphs, but it wouldn’t do that. I like Nigel’s approach to starting with properties as an array of arrays. I entered another Body Bullets style.

Thanks again, to the both of you.

Cheers