(* SmartString 1.12 Copyright 1994-2011 by Jon Pugh Jon's Home Page The best way to use this script is to load it from disk when you compile but check for updates when you run, like so: -- the alias follows the file if it's moved or renamed property ssFile : alias "YourDisk:Folder1:Folder2:SmartString" -- the modification date is burned in at compile time property ssDate : modification date of (info for ssFile) -- the script object is loaded at compile time too property ss : load script ssFile -- at run time check the mod date set modDate to modification date of (info for ssFile) -- if newer then load a new copy if modDate > ssDate then set SmartString to load script ssFile -- remember the date for the newly loaded file set ssDate to modDate --display dialog "I'm loaded" end if tell ss's SmartString setString("Your text here") -- do stuff end tell SmartString is an AppleScript script object which knows how to perform numerous operations on strings. The complete list of operations are: newString(aString) --> script object factory method getString() --> string (only reads) setString(aString) --> string setList(aList, seperator) --> string convertListToString(aList, delim) --> string (only reads) containsString(aString) --> boolean (only reads) subString(x, y) --> string (only reads) beforeString(subString) --> string (only reads) afterString(subString) --> string (only reads) betweenStrings(afterThis, beforeThis) --> string (only reads) appendString(aString) --> string prependString(aString) --> string insertBefore(subString, thisString) --> string insertAfter(subString, thisString) --> string deleteCharacters(x, y) --> string deleteString(subString) --> string deleteBefore(beforeString) --> string deleteAfter(afterString) --> string deleteBetween(beforeThis, afterThis) --> string keepBefore(beforeString) --> string keepAfter(afterString) --> string keepBetween(beforeThis, afterThis) --> string replaceString(subString, withString) --> string replaceStrings(subString, withString) --> string replaceBetween(frontTag, rearTag, newValue) --> string getTokens(delim) --> list (only reads) setTokens(aList, delim) --> string beforeToken(token, delim) --> string (only reads) afterToken(token, delim) --> string (only reads) getTokenRange(startIndex, endIndex, delim) --> list (only reads) deleteTokenRange(startIndex, endIndex, delim) --> string keepTokenRange(startIndex, endIndex, delim) --> string firstToken(delim) --> string (only reads) deleteFirstToken(delim) --> string keepFirstToken(delim) --> string lastToken(delim) --> string (only reads) deleteLastToken(delim) --> string keepLastToken(delim) --> string NthToken(n, delim) --> string (only reads) deleteNthToken(n, delim) --> string keepNthToken(n, delim) --> string trimWhitespace() --> string uppercase() --> string lowercase() --> string titlecase() --> string smartenQuotes() --> string *) script SmartString property parent : AppleScript property theString : "" on newString(aString) --> script object factory method copy me to anObject anObject's setString(aString) return anObject end newString on getString() --> string (only reads) return theString end getString on setString(aString) --> string set theString to aString as string end setString on setList(aList, seperator) --> string set theString to convertListToString(aList, seperator) end setList on subString(x, y) --> string (only reads) return text x thru y of theString end subString on containsString(aString) set foo to offset of aString in theString return foo > 0 end containsString on beforeString(aString) --> string (only reads) set foo to offset of aString in theString if foo = 0 then return "" else if foo = 1 then return "" else return text 1 thru (foo - 1) of theString end if end beforeString on afterString(aString) --> string (only reads) set foo to offset of aString in theString if foo = 0 then return "" else copy foo + (length of aString) to foo if foo > length of theString then return "" else return text foo thru -1 of theString end if end if end afterString on betweenStrings(afterThis, beforeThis) --> string (only reads) set savedString to theString keepAfter(afterThis) keepBefore(beforeThis) set tempString to theString setString(savedString) return tempString end betweenStrings on appendString(aString) --> string set theString to theString & aString end appendString on prependString(aString) --> string set theString to aString & theString end prependString on replaceString(thisStr, thatStr) -- syntax forgivenness so you don't have to remember if there is or isn't an s replaceStrings(thisStr, thatStr) -- expecting only a single replacement could be considered here, but we're not that subtle yet end replaceString on replaceStrings(thisStr, thatStr) --> string set oldDelim to AppleScript's text item delimiters set AppleScript's text item delimiters to thisStr set theList to text items of theString set AppleScript's text item delimiters to thatStr set theString to theList as string set AppleScript's text item delimiters to oldDelim return theString end replaceStrings on deleteString(aString) --> string set foo to offset of aString in theString if foo ≠ 0 then set theString to beforeString(aString) & afterString(aString) as string end if return theString end deleteString on replaceBetween(frontTag, rearTag, newValue) --> string set t1 to beforeString(frontTag) deleteBefore(frontTag) deleteString(frontTag) deleteBefore(rearTag) set theString to {t1, frontTag, newValue, theString} as string end replaceBetween on insertBefore(beforeStr, thisStr) --> string set theString to {beforeString(beforeStr), thisStr, beforeStr, afterString(beforeStr)} as string end insertBefore on insertAfter(afterStr, thisStr) --> string set theString to {beforeString(afterStr), afterStr, thisStr, afterString(afterStr)} as string end insertAfter on deleteBefore(beforeStr) --> string set theString to beforeStr & afterString(beforeStr) end deleteBefore on deleteAfter(afterStr) --> string set theString to beforeString(afterStr) & afterStr end deleteAfter on deleteBetween(afterThis, beforeThis) --> string set theString to {beforeString(beforeThis), beforeThis, afterThis, afterString(afterThis)} as string end deleteBetween on keepBefore(beforeStr) --> string set theString to beforeString(beforeStr) end keepBefore on keepAfter(afterStr) --> string set theString to afterString(afterStr) end keepAfter on keepBetween(afterThis, beforeThis) --> string set theString to betweenStrings(afterThis, beforeThis) end keepBetween on deleteCharacters(x, y) --> string if x > 1 then set a to text 1 thru (x - 1) of theString else set a to "" end if if y < length of theString then set b to text (y + 1) thru -1 of theString else set b to "" end if set theString to a & b end deleteCharacters on convertListToString(aList, delim) --> string (only reads) set oldSep to AppleScript's text item delimiters set AppleScript's text item delimiters to delim set aString to aList as string set AppleScript's text item delimiters to oldSep return aString end convertListToString on getTokens(delim) --> list (only reads) set oldDelim to AppleScript's text item delimiters set AppleScript's text item delimiters to delim set theList to text items of theString set AppleScript's text item delimiters to oldDelim return theList end getTokens on setTokens(aList, delim) --> string set theString to convertListToString(aList, delim) end setTokens on firstToken(delim) --> string (only reads) return NthToken(1, delim) end firstToken on lastToken(delim) --> string return NthToken(-1, delim) end lastToken on NthToken(n, delim) --> string if n = 0 then error "Cannot get delim zero" set t to getTokens(delim) if t = {} then return "" set numItems to number of items of t if n > numItems then error "Cannot get delim " & n & ", only " & numItems & " of tokens" return item n of t end NthToken on deleteNthToken(n, delim) --> string if n = 0 then error "Cannot delete token zero" set aList to getTokens(delim) set m to number of items of aList if n = 1 then set aList to items 2 thru m of aList else if n < 0 then set aList to items 1 thru (m + n) of aList else if n = m then set aList to items 1 thru (m - 1) of aList else set aList to (items 1 thru (n - 1) of aList) & (items (n + 1) thru m of aList) end if set oldDelim to AppleScript's text item delimiters set AppleScript's text item delimiters to delim try set theString to aList as string on error theMsg number theNum set AppleScript's text item delimiters to oldDelim error theMsg number theNum end try set AppleScript's text item delimiters to oldDelim return theString end deleteNthToken on deleteFirstToken(delim) --> string deleteNthToken(1, delim) end deleteFirstToken on deleteLastToken(delim) --> string deleteNthToken(-1, delim) end deleteLastToken on keepFirstToken(delim) --> string setString(NthToken(1, delim)) end keepFirstToken on keepLastToken(delim) --> string setString(NthToken(-1, delim)) end keepLastToken on keepNthToken(n, delim) --> string setString(NthToken(n, delim)) end keepNthToken on getTokenRange(startIndex, endIndex, delim) --> list (only reads) set theList to getTokens(delim) -- check parameter constraints set n to number of items of theList if abs(startIndex) > n or startIndex = 0 then error "Bad startIndex in getTokenRange" if abs(endIndex) > n or endIndex = 0 then error "Bad endIndex in getTokenRange" if startIndex > endIndex then error "startIndex > endIndex in getTokenRange" -- return sub-list return items startIndex thru endIndex of theList end getTokenRange on deleteTokenRange(startIndex, endIndex, delim) --> string set theList to getTokens(delim) -- check parameter constraints set n to number of items of theList if abs(startIndex) > n or startIndex = 0 then error "Bad startIndex in deleteTokenRange" if abs(endIndex) > n or endIndex = 0 then error "Bad endIndex in deleteTokenRange" if startIndex > endIndex then error "startIndex > endIndex in deleteTokenRange" if startIndex < 0 then set startIndex to n + startIndex + 1 if endIndex < 0 then set endIndex to n + endIndex + 1 -- return sub-lists if startIndex = 1 then if endIndex = n then set theList to {} else set theList to items (endIndex + 1) thru n of theList end if else if endIndex = n then set theList to items 1 thru (startIndex - 1) of theList else set theList to (items 1 thru (startIndex - 1) of theList) & (items (endIndex + 1) thru n of theList) end if setTokens(theList, delim) end deleteTokenRange on keepTokenRange(startIndex, endIndex, delim) --> string set theList to getTokenRange(startIndex, endIndex, delim) setTokens(theList, delim) end keepTokenRange on beforeToken(token, delim) --> string (only reads) set theList to getTokens(delim) set n to number of items of theList repeat with i from 2 to n if item i of theList = token then set aList to items 1 thru (i - 1) of theList return convertListToString(aList, delim) end if end repeat return "" end beforeToken on afterToken(token, delim) --> string (only reads) set theList to getTokens(delim) set n to number of items of theList repeat with i from 1 to (n - 1) if item i of theList = token then set aList to items (i + 1) thru n of theList return convertListToString(aList, delim) end if end repeat return "" end afterToken on trimWhitespace() --> string set twoReturns to return & return repeat while theString contains twoReturns replaceString(twoReturns, return) end repeat set twoTabs to tab & tab repeat while theString contains twoTabs replaceString(twoTabs, tab) end repeat set twoSpaces to space & space repeat while theString contains twoSpaces replaceString(twoSpaces, space) end repeat if length of theString > 1 then repeat while character 1 of theString = tab or character 1 of theString = space set theString to text 2 thru -1 of theString end repeat repeat while last character of theString = tab or last character of theString = space set theString to text 1 thru -2 of theString end repeat end if return theString end trimWhitespace -- this is a list of commonly used accented chars and their uppercase equivalents -- we'll only swap these known pairs as well as the ASCII alphabet property lowers : "œæáàâäãåéèêëóòôöõúùûüíìîïñçøÿπß" property uppers : "ŒÆÁÀÂÄÃÅÉÈÊËÓÒÔÖÕÚÙÛÜÍÌÎÏÑÇØŸ∏ẞ" on uppercase() --> string local newString set newString to "" set ncl to number of characters of lowers considering case repeat with c in characters of theString set found to false set a to id of c -- handle ascii case if a > 96 and a < 123 then set a to a - 32 set newString to newString & (character id a) set found to true end if if (not found) and (a > 128) then -- handle known accented characters repeat with lc from 1 to ncl if contents of c = character lc of lowers then set newString to newString & character lc of uppers set found to true exit repeat end if end repeat end if if not found then set newString to newString & c end if end repeat end considering set theString to newString end uppercase on lowercase() --> string set newString to "" set ncl to number of characters of uppers considering case repeat with c in characters of theString set found to false set a to id of c -- handle ascii case if a > 64 and a < 91 then set a to a + 32 set newString to newString & (character id a) set found to true end if if (not found) and (a > 128) then -- handle known accented characters repeat with lc from 1 to ncl if contents of c = character lc of uppers then set newString to newString & character lc of lowers set found to true exit repeat end if end repeat end if if not found then set newString to newString & c end if end repeat end considering set theString to newString end lowercase on titlecase() --> string -- Set All Words To Start With Upper Case set newString to "" set ncl to number of characters of uppers set firstChar to true -- start with first char considering case repeat with c in characters of theString set found to false set a to id of c -- tab, vertical tab, space, double quote, single quote, non-breaking space, left single quote, left double quote if a is in {9, 11, 32, 34, 39, 160, 2018, 8220} then set firstChar to true else -- handle ascii case if a > 64 and a < 91 and not firstChar then -- upper to lower set a to a + 32 set newString to newString & (character id a) set found to true else if a > 96 and a < 123 and firstChar then -- lower to upper set a to a - 32 set newString to newString & (character id a) set found to true end if if (not found) and (a > 128) then -- handle known accented characters if not firstChar then -- upper to lower repeat with lc from 1 to ncl if contents of c = character lc of uppers then set newString to newString & character lc of lowers set found to true exit repeat end if end repeat else -- lower to upper repeat with lc from 1 to ncl if contents of c = character lc of lowers then set newString to newString & character lc of uppers set found to true exit repeat end if end repeat end if end if set firstChar to false end if if not found then set newString to newString & c end if end repeat end considering set theString to newString end titlecase on abs(n) if n < 0 then return -n else return n end if end abs on isWhiteSpace(c) return c = space or c = tab or c = return or c = linefeed end isWhiteSpace property gLeftApostrophe : character id 8216 property gRightApostrophe : character id 8217 property gLeftQuote : character id 8220 property gRightQuote : character id 8221 property singleQuote : "'" property doubleQuote : "\"" on smartenQuotes() set newString to {} set n to number of characters of theString set s to theString set prevChar to "" repeat with i from 1 to n set theChar to character i of theString if (theChar = singleQuote or theChar = doubleQuote) then if (prevChar = 0 or ¬ prevChar = "(" or prevChar = "[" or prevChar = "{" or ¬ prevChar = "<" or prevChar = 171 or ¬ prevChar = character id 12296 or prevChar = character id 12298 or ¬ (prevChar = gLeftQuote and theChar = singleQuote) or ¬ (prevChar = gLeftApostrophe and theChar = doubleQuote) or ¬ isWhiteSpace(prevChar)) then if theChar = singleQuote then set theChar to gLeftApostrophe else set theChar to gLeftQuote end if else if theChar = singleQuote then set theChar to gRightApostrophe else set theChar to gRightQuote end if end if set prevChar to theChar as string end if copy theChar to end of newString end repeat setString(newString as string) return getString() end smartenQuotes end script