TweetFollow Us on Twitter

Working With Text

Volume Number: 21 (2005)
Issue Number: 7
Column Tag: Programming

AppleScript Essentials

Working With Text

by Benjamin S. Waldie

When writing AppleScript code, many of the things that you will automate will involve working with and manipulating text in some manner. For example, you might need to write a script that will retrieve text content from a FileMaker Pro database, and then place that content into an Adobe InDesign document. You may need to maintain a text-based log file of your script's activity during processing, or you may need a script that will extract content from email messages, and write the content to files on a server.

During this month's article, we will discuss a number of ways to work with text, including ways to break text apart, search text, and read from and write to files.

About Text in AppleScript

Much like a scriptable application in the Mac OS, the AppleScript language itself possesses classes and commands. These classes and commands are considered to be the core language of AppleScript, and are used, interspersed with application and scripting addition terminology, to make up your scripts. For a detailed overview of AppleScript's core language, you should refer to The AppleScript Language Guide, which is available through Apple's Developer Connection at http://developer.apple.com/documentation/AppleScript/.

In AppleScript, text is considered to be a class, and is synonymous with the class string. Because of this, throughout this article, I will use the term string when referring to text.

class of ("This is some text" as text)
--> string

Just like classes in applications, AppleScript core language classes can possess properties. A string possesses a length property, which may be used in order to determine the number of characters contained within the string. For example:

length of "This is some text"
--> 17

Manipulating Text

When working with a string in AppleScript, one of the things that you will probably want to do is to manipulate it, or break it apart in some way. For example, you might need to write code that will parse a tab-delimited file, extracting field information. Once broken apart, it can be repurposed, merged back together in various ways, and more.

Elements of a String

In AppleScript, paragraphs, words, characters, and text are all considered to be elements of the class string. Because of this, a string can be broken up in a number of different ways. The following examples show some of the ways that a string can be broken up by referencing its elements.

The following example code will retrieve a paragraph from a specified string:

set theText to "This is paragraph 1 of some text.
This is paragraph 2 of some text."

set theParagraph to paragraph 2 of theText
--> "This is paragraph 2 of some text."

The following example code will retrieve a word from the string specified above:

word 3 of theText
--> "paragraph"

The following example code will retrieve a character from the string specified above:

character 9 of theText
--> "p"

You may also choose to retrieve multiple elements of a string at once. The following code will retrieve a specified set of characters from the string specified above:

characters 1 thru 9 of theText
--> {"T", "h", "i", "s", " ", "i", "s", " ", "p"}

When retrieving elements in this manner, you will notice that the result is provided as a list. When retrieving words or paragraphs in this manner, a list may suffice. However, when retrieving characters, you may prefer a string instead. To retrieve a list of characters as a string, you could coerce the retrieved list back to a string. You could also reference the text element of the string, rather than the character element. For example:

(characters 1 thru 9 of theText) as string
--> "This is p"

text 1 thru 9 of theText
--> "This is p"

Using the Offset Command

At times, you may need to determine the location of a specific character, word, or string within a longer string. While this could be accomplished by using a repeat statement to loop through the characters of the string until the specified search string is found, a more efficient way would be to use the offset command. The offset command is included in the String Commands suite in the Standard Additions scripting addition that is installed with Mac OS X.

set theFileName to "filename.jpg"

offset of "." in theFileName
--> 9

As you can see from the example code above, the offset command will return the position of the first instance of a specified string within another string. With this value, you can then retrieve specific parts of the string. For example, the following sample code will extract the prefix before a specified character in the string that we used above.

text 1 thru (offset of "." in theFileName) of theFileName
--> "filename."

Note in the example above, that the extracted prefix actually contains the delimiter character. Again, this is because the offset command will return the actual position of the first instance of the specified string. In order to extract the prefix without the delimiter, then you must subtract 1 from the offset. For example:

set thePrefix to text 1 thru ((offset of "." in theFileName) - 1) of theFileName
--> "filename"

You may also add 1 to the offset, and extract text from that location until the end of the string, in order to retrieve the suffix following the delimiter. For example:

set theSuffix to text ((offset of "." in theFileName) + 1) thru -1 of theFileName
--> "jpg"

Again, the offset command will return the position of only the first instance of a specified string. However, what if a string contains multiple delimiters, and you want to break the text apart based on the offset of the last delimiter? To do this, you can extract the characters of the string in list format, then reverse them using the reverse property of a list. Next, you can change the reversed characters back to a string, extract the prefix and suffix, and then reverse them back. This sounds complicated, but it can actually be done in only a few lines of code. The following example code will walk you through the process.

This example code will extract the characters of the string:

set theFileName to "file.name.jpg"
set theCharacters to characters of theFileName
--> {"f", "i", "l", "e", ".", "n", "a", "m", "e", ".", "j", "p", "g"}

This example code will reverse the extracted characters:

set theReversedCharacters to reverse of theCharacters
--> {"g", "p", "j", ".", "e", "m", "a", "n", ".", "e", "l", "i", "f"}

This example code will convert the reversed characters back to a string:

set theReversedFileName to theReversedCharacters as string
--> "gpj.eman.elif"

This example code will locate the delimiter in the reversed string, using the offset command:

set theOffset to offset of "." in theReversedFileName
--> 4

This example code will retrieve the prefix and suffix from the reversed string:

set theReversedSuffix to text 1 thru (theOffset - 1) of theReversedFileName
--> "gpj"

set theReversedPrefix to text (theOffset + 1) thru -1 of theReversedFileName
--> "eman.elif"

This example code will reverse the extracted prefix and suffix back to their original form:

set thePrefix to (reverse of (characters of theReversedPrefix)) as string
--> "file.name"

set theSuffix to (reverse of (characters of theReversedSuffix)) as string
--> "jpg"

Now, you should have the properly retrieved prefix and suffix. The example code above could actually have been written in a more condensed fashion. It was intentionally written in a verbose manner for demonstration purposes. For example, the following code will perform the same function, but has been condensed into fewer lines of code:

set theFileName to "file.name.jpg"
set theReversedFileName to (reverse of (characters of theFileName)) as string
set theOffset to offset of "." in theReversedFileName
set thePrefix to (reverse of (characters (theOffset + 1) 
   thru -1 of theReversedFileName)) as string
set theSuffix to (reverse of (characters 1 thru (theOffset - 1) 
   of theReversedFileName)) as string

Another thing to note when working with the offset command is that in some cases, you may attempt to get the offset of a string that does not exist with the string you are evaluating. If this occurs, the offset command will return a value of 0. For example:

offset of "." in "filename"
--> 0

As you begin using the offset command, be sure to add code to handle this type of situation, should it occur.

Using AppleScript's Text Item Delimiters

Another way of breaking text apart is by making use of AppleScript's text item delimiters property, which is actually a property of AppleScript itself, and can be retrieved or changed at any time. AppleScript's text item delimiters property contains the delimiter that is used to separate chunks of text within a string. By default, AppleScript's text item delimiters property is set to a value of {""}, essentially an empty string.

Though AppleScript's text item delimiters may be set to a list containing multiple values, AppleScript will only utilize the first value in the list. For this reason, when setting AppleScript's text item delimiters, it is not necessary to specify a list. Rather, a string may be used, as you will see in the next code example.

AppleScript's text item delimiters
--> {""}

A character is the smallest element within a string. Since AppleScript's text item delimiters are set to an empty string by default, retrieving the text elements from a string will return the characters from within that string in list format.

The following example code will demonstrate how AppleScript's text item delimiters may be changed in order to break apart a string. Please note that modifying this property of AppleScript may affect other code in your script. Therefore, you should always be sure to set the value of the property back to its default value when you are done manipulating your string.

set theText to "01.01.2005"
set AppleScript's text item delimiters to "."
set theTextItems to text items of theText
set AppleScript's text item delimiters to {""}
theTextItems
--> {"01", "01", "2005"}

As you can see, the example code above can be used to convert a string to a list, using a specified delimiter. So, using this method, you could easily write code that would convert a tab delimited string into a list of fields.

The AppleScript's text item delimiters property may also be used to coerce a list of values back to a string. The following example code will take the list output by the previous example, and change it back to a string, using a different delimiter.

set theTextItems to {"01", "01", "2005"}
set AppleScript's text item delimiters to "-"
set theText to theTextItems as string
set AppleScript's text item delimiters to {""}
theText
--> "01-01-2005"

Now that we have explored ways to convert a string to a list and back, we can take things a step further. The following example code will perform a find and replace within a string.

set theText to "01-01-2005"
set AppleScript's text item delimiters to "-"
set theTextItems to text items of theText
set AppleScript's text item delimiters to "/"
set theText to theTextItems as string
set AppleScript's text item delimiters to {""}
theText
--> "01/01/2005"

In the example code above, every instance of the "-" character is replaced with the "/" character.

In all of the examples above, we were working with a single character as our delimiter. If desired, you may set AppleScript's text item delimiters to a longer string containing multiple characters, such as a word or a paragraph.

Reading and Writing Text

Now that we have explored several ways to break apart and manipulate text, let's discuss ways to work with files through reading and writing.

Reading from a File

Reading from a file is done using a command found in the File Read/Write suite of the Standard Additions scripting addition. To read from a file, use the read command.

set theFile to choose file with prompt "Select a text file:"
read theFile

The example code above will prompt you to select a text file. Next, it will read the file and return the entire contents of the file as a string.

When reading from a file, you may optionally choose to use the open for access command, also found in the File Read/Write suite, to open a file, prior to reading from it. By using this command to open a file prior to reading from it, the file will remain opened in memory until the script closes the file, using the close access command. For example:

set theFile to choose file with prompt "Select a text file:"
set theFileReference to open for access theFile
set theFileContents to read theFileReference
close access theFileReference

As you can see from the example code above, the open for access command returns a reference to the opened file. That reference can then be used to refer to the opened file, using the read and close access commands. It is important to always use the close access command when you are done working with a file. Otherwise, the file will remain opened, and may not be opened for access again until it is closed. This can potentially produce error messages in subsequent runs of the script.

When reading from a file, the read command offers some optional parameters. For best results with these parameters, you should use the open for access and close access commands, along with the read command. The from and to parameters will allow you to read a small portion of the file's contents. For example, the following example code will read a file up until the 10th character:

set theFile to choose file with prompt "Select a text file:"
set theFileReference to open for access theFile
set theFileContents to read theFileReference to 10
close access theFileReference

The following example code will read a file between two specified characters, in this case, the text between character 10 and character 20:

set theFile to choose file with prompt "Select a text file:"
set theFileReference to open for access theFile
set theFileContents to read theFileReference from 10 to 20
close access theFileReference

The until parameter will allow you to read a file until a specific character is detected. For example, the code below will read a file until a return character is detected.

set theFile to choose file with prompt "Select a text file:"
set theFileReference to open for access theFile
set theFileContents to read theFileReference until return
close access theFileReference

The using delimiter and using delimiters parameters will allow you to read a file using one or more specified delimiters. The result will be a list of strings, broken apart by the specified delimiter(s). This may be useful when reading a tab-delimited file directly, as it would allow you to break apart the file as it is read by the script. For example:

set theFile to choose file with prompt "Select a text file:"
set theFileReference to open for access theFile
set theFileContents to read theFileReference using delimiter tab
close access theFileReference

Some of optional parameters shown above possess additional functionalities that were not covered in this article. In addition, the read command also includes some other optional parameters, which may be useful in other situations. I encourage you to spend some additional time becoming familiar with all of the optional parameters of the read command.

Writing to a File

To write data to a file, you use the write command, also found in the File Read/Write suite. When using the write command, it is always necessary to use the open for access command prior to writing to the file. You cannot write to a file unless it has been opened first. In addition, when opening a file for writing, you must also specify the with write permission optional parameter for the open for access command. Otherwise, the file will be opened, but you will not be able to write to it.

The following example code will prompt the user to enter some text, and then write that text to a file on the desktop.

set theText to text returned of (display dialog "Please enter some text:" default answer "")
set theFilePath to (path to desktop as string) & "test.txt" as string
set theFileReference to open for access theFilePath with write permission
write theText to theFileReference
close access theFileReference

Like the read command, the write command also has some optional parameters, including the starting at parameter. This parameter will allow you to specify at what point in the file to begin writing. By default, the write command will start writing at the beginning of a file. To start writing at the end of a file, you may use the term eof, for end of file. You may also specify a numeric value for the starting at parameter, specifying the number of the character at which the script should begin writing.

The following example code will append a specified string to the end of a file:

set theText to text returned of (display dialog "Please enter some text:" default answer "")
set theFilePath to (path to desktop as string) & "test.txt" as string
set theFileReference to open for access theFilePath with write permission
write theText to theFileReference starting at eof
close access theFileReference

Optionally, you may want to use the set eof command, also found in the File Read/Write suite, in order to change the location of the end of the file. For example, the following code will set the end of the file to 0, wiping all existing content, prior to writing the new text.

set theText to text returned of (display dialog "Please enter some text:" default answer "")
set theFilePath to (path to desktop as string) & "test.txt" as string
set theFileReference to open for access theFilePath with write permission
set eof of theFileReference to 0
write theText to theFileReference starting at eof
close access theFileReference

In Closing

Now that we have explored some of the ways that you can manipulate text content, you can begin to experiment with these methods, and combine them together in order to perform more robust types of processing. For example, try creating a handler that will write specified content to a text file. Then, call that handler throughout a script to maintain a running activity log. You may find such a log to be useful in monitoring the script's activity, as well as for troubleshooting purposes.

For continued learning about working with text, be sure to review the AppleScript Language Guide, mentioned earlier. You will also find detailed documentation and additional examples in most AppleScript books, such as Danny Goodman's AppleScript Handbook, available from SpiderWorks, LLC at http://www.spiderworks.com.

Until next time, keep scripting!


Benjamin Waldie is president of Automated Workflows, LLC, a firm specializing in AppleScript and workflow automation consulting. In addition to his role as a consultant, Benjamin is an evangelist of AppleScript, and can frequently be seen presenting at Macintosh User Groups, Seybold Seminars, and MacWorld. For additional information about Benjamin, please visit http://www.automatedworkflows.com, or email Benjamin at applescriptguru@mac.com.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Adobe Acrobat Reader 20.012.20041 - View...
Adobe Acrobat Reader allows users to view PDF documents. You may not know what a PDF file is, but you've probably come across one at some point. PDF files are used by companies and even the IRS to... Read more
Adobe Acrobat DC 20.012.20041 - Powerful...
Acrobat DC is available only as a part of Adobe Creative Cloud, and can only be installed and/or updated through Adobe's Creative Cloud app. Adobe Acrobat DC with Adobe Document Cloud services is... Read more
Sketch 68 - Design app for UX/UI for iOS...
Sketch is an innovative and fresh look at vector drawing. Its intentionally minimalist design is based upon a drawing space of unlimited size and layers, free of palettes, panels, menus, windows, and... Read more
Bean 3.3.1 - Fast and uncluttered word p...
Bean is no longer being actively developed, but will be updated as necessary to patch bugs and maintain OS X compatibility Bean is lean, fast, and uncluttered. If you get depressed at the thought... Read more
RetroArch 1.9.0 - Game emulator.
RetroArch is most popularly known for being a program with which you can play many emulators and games, which have all been customized and tailor-ported to the libretro API. It is designed to be fast... Read more
NetNewsWire 5.0.4 - RSS and Atom news re...
NetNewsWire is the best way to keep up with the sites and authors you read most regularly. Let NetNewsWire pull down the latest articles, and read them in a distraction-free and Mac-like way. Native... Read more
EarthDesk 7.4.5 - $24.99
EarthDesk replaces your static desktop picture with a rendered image of Earth showing correct sun, moon, and city illumination. With an Internet connection, EarthDesk displays near-real-time global... Read more
BetterTouchTool 3.401 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom)... Read more
Vienna 3.5.6 :e12c952d: - RSS and Atom n...
Vienna is a freeware and Open-Source RSS/Atom newsreader with article storage and management via a SQLite database, written in Objective-C and Cocoa, for the OS X operating system. It provides... Read more
WhatsApp 2.2031.5 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more

Latest Forum Discussions

See All

Scrappers receives a major update that a...
Q-Games' Scrappers has received a fairly sizeable new update that adds fresh gameplay features and a host of quality-of-life tweaks. [Read more] | Read more »
Motorball is a car football game from No...
A few years back Noodlecake Studios announced that they would be dipping in the multiplayer gaming realm with two different games. The first of those, Golf Blitz, released a while back and has proven to be very popular. Now, the second has arrived... | Read more »
SINoALICE's latest update introduce...
SINoALICE's latest update has now arrived, adding several fan-favourite characters from popular RPG series NieR. Young Nier, Kaine, and Young Emil are available in-game as part of a limited-time crossover event set to run until August 20th. [Read... | Read more »
Rocat Jumpurr is an intense roguelite pl...
Rocat Jumpurr is a roguelite platformer from developer Mousetrap Games. You might already be familiar with it if you follow the Big Indie Pitch, where it won first place during this year's Pocket Gamer Connects London competition. Following its... | Read more »
PUBG Mobile's Play As One campaign...
Back in mid-July, we reported that PUGB Mobile had teamed up with Direct Relief to help raise money for the charity's COVID-19 response project. It focused on an in-game running challenge for players, which lead to the PUBG Mobile donating $2... | Read more »
Marvel Contest of Champions' latest...
Marvel Contest of Champions' latest motion comic has arrived, and it shows off new fighters Air-Walker and Dragon Man. Both characters are set to arrive in-game this month. [Read more] | Read more »
Clash Royale: The Road to Legendary Aren...
Supercell recently celebrated its 10th anniversary and their best title, Clash Royale, is as good as it's ever been. Even for lapsed players, returning to the game is as easy as can be. If you want to join us in picking the game back up, we've put... | Read more »
Global Spy is an intriguing 2D spy sim f...
Developer Yuyosoft Innovations' Global Spy launched last month for iOS and Android, though if you missed it at the time, we're here to tell you why it's well worth a go. This one's all about international espionage, tracking down elusive spies,... | Read more »
Distract Yourself With These Great Mobil...
There’s a lot going on right now, and I don’t really feel like trying to write some kind of pithy intro for it. All I’ll say is lots of people have been coming together and helping each other in small ways, and I’m choosing to focus on that as I... | Read more »
Hyena Squad is sci-fi turn-based strateg...
Wave Light Games has just revealed its latest release, Hyena Squad, a turn-based RPG set in a space station infested by gross aliens and the living dead. The announcement was first reported on by Touch Arcade. [Read more] | Read more »

Price Scanner via MacPrices.net

Apple drops prices on clearance 27″ 5K iMacs,...
Apple has dropped prices on Certified Refurbished 2019 27″ iMacs to a new low of $1439 and up to $520 off their original MSRP. Apple’s one-year warranty is standard and shipping is free. The... Read more
Price drop: Clearance 8-core iMac Pro for $38...
Apple has dropped their price on Certified Refurbished 27″ 3.2GHz 8-Core iMac Pros to $3819 including free shipping. Their price is $1180 off the original MSRP of new models. A standard Apple one-... Read more
Monday sale: New 13″ 2.0GHz MacBook Pros for...
Amazon has new 2020 13″ 2.0GHz/512GB MacBook Pros back in stock on sale today for $200 off Apple’s MSRP. Shipping is free. Be sure to purchase the MacBook Pro from Amazon, rather than a third-party... Read more
Sale! Apple’s 16″ MacBook Pros for up to $349...
Apple Authorized Reseller Adorama has new 2019 16″ MacBook Pros in stock on sale today for $100-$349 off Apple’s MSRP, each including free shipping. Their prices for 8-core models ($349 off) are the... Read more
Save hundreds of dollars on a custom-configur...
Save up to $920 on a custom-configured 16″ MacBook Pro with these Certified Refurbished models that Apple has restocked today. Each MacBook Pro features a new outer case, free shipping, and includes... Read more
New 2020 12.9″ iPad Pros on sale for up to $8...
Apple reseller Expercom has new 2020 Apple 12.9″ iPad Pros on sale today for $60-$85 off MSRP, with prices starting at $939. These are the same iPad Pros sold by Apple in their retail and online... Read more
Woot offers numerous 2018-2020 MacBook Pros a...
Amazon-owned Woot has many open-box return MacBook Airs and MacBook Pros available today at prices starting at $879. Shipping is free for Prime members. Here’s what they have as of this post, and... Read more
Apple restocks refurbished 2020 13″ MacBook A...
Apple has restocked Certified Refurbished 2020 13″ MacBook Airs starting at only $849 and up to $200 off the cost of new Airs. Each MacBook features a new outer case, comes with a standard Apple one-... Read more
Apple restocks clearance 2019 13″ 2.4GHz MacB...
Apple has restocked Certified Refurbished 2019 13″ 2.4GHz 4-Core Touch Bar MacBook Pros starting at $1359 and up to $560 off original MSRP. Apple’s one-year warranty is included, shipping is free,... Read more
Apple restocks refurbished iPhone XR models s...
Apple has restocked Certified Refurbished, unlocked, iPhone XR models in the refurbished section of their online store starting at $539. Each iPhone comes with Apple’s standard one-year warranty,... Read more

Jobs Board

Cub Foods - *Apple* Valley - Now Hiring Par...
Cub Foods - Apple Valley - Now Hiring Part Time! United States of America, Minnesota, Apple Valley New Retail Post Date 6 days ago Requisition # 122305 Sign Up Read more
Director of *Apple* Enterprise Operations -...
## Description JOB SUMMARY: The Director of Apple Enterprise Operations is responsible for developing and managing the overall strategy, operation and management of Read more
Cub Foods - *Apple* Valley - Now Hiring Par...
Cub Foods - Apple Valley - Now Hiring Part Time! United States of America, Minnesota, Apple Valley New Retail Post Date 5 days ago Requisition # 122305 Sign Up Read more
Blue *Apple* Cafe Student Worker - Fall - P...
…to enhance your work experience. Student positions are available at the Blue Apple Cafe. Employee meal discount during working hours is provided. Duties include food Read more
Cub Foods - *Apple* Valley - Now Hiring Par...
Cub Foods - Apple Valley - Now Hiring Part Time! United States of America, Minnesota, Apple Valley New Retail Post Date 4 days ago Requisition # 122305 Sign Up Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.