Adrian Nier Code

Back to overview

Title case

Last modification: Tuesday, September 02, 2008 08:35 am

Converts a string to title case.

Required parameters
Parameter 1 (string)
A string that is converted to title case.

Implementation

on titlecase(_string)
   
   script TitleCase_Extras
      
      property pCONVERT_REST_TO_LOWERCASE : true
      
      property pLOWERCASE_CHARACTERS : {}
      property pUPPERCASE_CHARACTERS : {}
      property pKEEP_LOWERCASE : {}
      property pSPECIAL_WORDS : {}
      property pSPECIAL_PHRASES : {}
      property pCHARS_CAUSING_UPPERCASE_FOR_NEXT_CHAR : {}
      property pLAST_CHARS_CAUSING_UPPERCASE_FOR_NEXT_WORD : {}
      property pCHARACTERS_THAT_BREAK_WORDS : {}
      
      
      on init()
         -- Define list of words to keep lower case
         set pKEEP_LOWERCASE to {}
         set pKEEP_LOWERCASE to pKEEP_LOWERCASE & {"a", "an", "and", "as", "at"}
         set pKEEP_LOWERCASE to pKEEP_LOWERCASE & {"but", "by"}
         set pKEEP_LOWERCASE to pKEEP_LOWERCASE & {"en"}
         set pKEEP_LOWERCASE to pKEEP_LOWERCASE & {"featuring", "feat.", "feat", "for"}
         set pKEEP_LOWERCASE to pKEEP_LOWERCASE & {"if", "in"}
         set pKEEP_LOWERCASE to pKEEP_LOWERCASE & {"of", "on", "or"}
         set pKEEP_LOWERCASE to pKEEP_LOWERCASE & {"the", "to"}
         set pKEEP_LOWERCASE to pKEEP_LOWERCASE & {"v", "v.", "via", "vs", "vs."}
         
         -- Define list of special phrases
         set pSPECIAL_PHRASES to {"iPod touch", "Mac mini", "(featuring", "[featuring", "(feat.", "[feat.", "(feat", "[feat."}
         
         -- Define list of special words
         set pSPECIAL_WORDS to {"iBook", "iDVD", "iLife", "iMac", "iMovie", "iPhone", "iPhoto", "iPod", "iWeb", "iWork", "eMac", "eMail", "AT&T", "Q&A"}
         
         -- Define characters that require the next character to be upper case
         set pCHARS_CAUSING_UPPERCASE_FOR_NEXT_CHAR to {"\"", "'", "“", "‘", "(", "{", "[", "_"}
         
         -- Define characters that are the last character of one word and require the next word to be upper case
         set pLAST_CHARS_CAUSING_UPPERCASE_FOR_NEXT_WORD to {":", ".", "?", "!"}
         set pCHARACTERS_THAT_BREAK_WORDS to {":", "-", return}
         
         -- Generate variations for special words
         set _originalSpecialWordsCount to count of pSPECIAL_WORDS
         set _wordAndPhraseAdditions to {"'s", "’s", "s'", "s’", "s", "es"}
         repeat with _i from 1 to count of _wordAndPhraseAdditions
            repeat with _j from 1 to _originalSpecialWordsCount
               set end of pSPECIAL_WORDS to (item _j of pSPECIAL_WORDS & item _i of _wordAndPhraseAdditions)
            end repeat
         end repeat
         
         -- Generate variations for special phrases
         set _originalSpecialPhrasesCount to count of pSPECIAL_PHRASES
         repeat with _i from 1 to count of _wordAndPhraseAdditions
            repeat with _j from 1 to _originalSpecialPhrasesCount
               set end of pSPECIAL_PHRASES to (item _j of pSPECIAL_PHRASES & item _i of _wordAndPhraseAdditions)
            end repeat
         end repeat
         -- Reverse the list of phrases so that "Mac minis" produces a positive match before "Mac mini" does.
         set pSPECIAL_PHRASES to reverse of pSPECIAL_PHRASES
         
         -- Define character sets
         set _lowercaseCharacters to "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"
         set _uppercaseCharacters to "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"
         -- Add special characters by using their ASCII numbers
         -- Currently scripts encoded into applescript:// protocol URLs do not open in Script Editor when they contain high-ascii characters
         set _lowercaseSpecialCharacters to {138, 140, 136, 139, 135, 137, 190, 141, 142, 144, 145, 143, 146, 148, 149, 147, 150, 154, 155, 151, 153, 152, 207, 159, 156, 158, 157, 216}
         set _uppercaseSpecialCharacters to {128, 129, 203, 204, 231, 229, 174, 130, 131, 230, 232, 233, 234, 235, 236, 237, 132, 133, 205, 238, 239, 241, 206, 134, 242, 243, 244, 217}
         
         -- Convert comma seperated strings into a list
         set AppleScript's text item delimiters to ","
         set _lowercaseCharacters to text items of _lowercaseCharacters
         set _uppercaseCharacters to text items of _uppercaseCharacters
         
         -- Add special characters to the character lists
         repeat with _i from 1 to count of _lowercaseSpecialCharacters
            set end of _lowercaseCharacters to ASCII character (item _i of _lowercaseSpecialCharacters)
         end repeat
         repeat with _i from 1 to count of _uppercaseSpecialCharacters
            set end of _uppercaseCharacters to ASCII character (item _i of _uppercaseSpecialCharacters)
         end repeat
         
         set pLOWERCASE_CHARACTERS to _lowercaseCharacters
         set pUPPERCASE_CHARACTERS to _uppercaseCharacters
         
         
      end init
      
      on protectSpecialPhrases(_string)
         repeat with _i from 1 to count of pSPECIAL_PHRASES
            set _string to searchAndReplace(_string, (item _i of pSPECIAL_PHRASES), "<TCProtectedSpecialPhrase" & paddedString((_i as string), "0", (count of ((count of pSPECIAL_PHRASES) as string))) & ">")
         end repeat
         return _string
      end protectSpecialPhrases
      
      
      on restoreSpecialPhrases(_string)
         set _prvDlmt to AppleScript's text item delimiters
         set AppleScript's text item delimiters to "<TCProtectedSpecialPhrase"
         set _stringItems to text items of _string
         set AppleScript's text item delimiters to _prvDlmt
         
         set _restoredItems to {item 1 of _stringItems}
         if (count of _stringItems) > 1 then
            repeat with _i from 2 to count of _stringItems
               set _prvDlmt to AppleScript's text item delimiters
               set AppleScript's text item delimiters to ">"
               try
                  set _phraseNumber to text item 1 of (item _i of _stringItems) as integer
                  set _stringRemainder to text items 2 thru -1 of (item _i of _stringItems) as string
               on error
                  set _phraseNumber to 0
               end try
               
               set AppleScript's text item delimiters to _prvDlmt
               
               if _phraseNumber ≠ 0 then
                  set end of _restoredItems to (item _phraseNumber of pSPECIAL_PHRASES & _stringRemainder)
               else
                  set end of _restoredItems to (item _i of _stringItems)
               end if
            end repeat -- with _i from 2 to count of _stringItems
         end if --  count of _stringItems > 1
         
         set _prvDlmt to AppleScript's text item delimiters
         set AppleScript's text item delimiters to ""
         set _restoredItems to _restoredItems as string
         set AppleScript's text item delimiters to _prvDlmt
         
         return _restoredItems
      end restoreSpecialPhrases
      
      on process(_string, _previousString, _nextString)
         
         repeat with _i from 1 to count of pCHARACTERS_THAT_BREAK_WORDS
            if _string contains (item _i of pCHARACTERS_THAT_BREAK_WORDS) then
               return breakAndProcess(_string, _previousString, _nextString, (item _i of pCHARACTERS_THAT_BREAK_WORDS))
            end if
         end repeat
         
         
         set _type to actionForString(_string, _previousString, _nextString)
         if _type is "TCUppercaseFirstChar" then
            return uppercaseFirstChar(_string)
            
         else if _type is "TCReplaceWithSpecialWord" then
            return specialWord(_string)
            
         else if _type is "TCUppercaseSecondChar" then
            return uppercaseSecondChar(_string)
            
         else if _type is "TCLowercase" then
            return lowercase(_string)
            
         else if _type is "TCUppercase" then
            return uppercase(_string)
            
         else if _type is "TCNoChange" then
            return _string
            
         else
            if pCONVERT_REST_TO_LOWERCASE then set _string to lowercase(_string)
            return _string
            
         end if
         
      end process
      
      on actionForString(_string, _previousString, _nextString)
         
         if _previousString is "" then set _previousString to " "
         
         if _string is "" then
            return "TCNoChange"
            
         else if _string starts with "<TCProtectedSpecialPhrase" then
            return "TCNoChange"
            
         else if _string is in pSPECIAL_WORDS then
            return "TCReplaceWithSpecialWord"
            
         else if isRomanNumeral(_string) then
            return "TCUppercase"
            
         else if isAbbreviation(_string) then
            return "TCUppercase"
            
         else if isEmailAddress(_string) then
            return "TCLowercase"
            
         else if isProtocol(_string) then
            return "TCLowercase"
            
         else if containsInsideDot(_string) then
            return "TCNoChange"
            
         else if (character 1 of _string) is in pCHARS_CAUSING_UPPERCASE_FOR_NEXT_CHAR then
            return "TCUppercaseSecondChar"
            
         else if _previousString is false then
            return "TCUppercaseFirstChar"
            
         else if (character -1 of _previousString) is in pLAST_CHARS_CAUSING_UPPERCASE_FOR_NEXT_WORD then
            return "TCUppercaseFirstChar"
            
         else if _nextString is false or _nextString is return then
            return "TCUppercaseFirstChar"
            
         else if _string is in pKEEP_LOWERCASE then
            return "TCLowercase"
            
         else
            return "TCUppercaseFirstChar"
            
         end if
         
      end actionForString
      
      on breakAndProcess(_string, _previousString, _nextString, _breakCharacter)
         
         set _prvDlmt to AppleScript's text item delimiters
         set AppleScript's text item delimiters to _breakCharacter
         set _stringItems to text items of _string
         set AppleScript's text item delimiters to _prvDlmt
         
         set _convertedStringItems to {}
         repeat with _i from 1 to count of _stringItems
            try
               set _nextString to item (_i + 1) of _stringItems
            on error
               set _nextString to false
            end try
            set _string to process((item _i of _stringItems), _previousString, _nextString)
            
            set _previousString to _string
            set end of _convertedStringItems to _string
         end repeat
         set _prvDlmt to AppleScript's text item delimiters
         set AppleScript's text item delimiters to _breakCharacter
         set _string to _convertedStringItems as string
         set AppleScript's text item delimiters to _prvDlmt
         
         return _string
         
      end breakAndProcess
      
      
      
      on uppercaseFirstChar(_string)
         
         if pCONVERT_REST_TO_LOWERCASE then set _string to lowercase(_string)
         
         set _firstChar to uppercase(character 1 of _string)
         if (count of characters in _string) < 2 then
            set _remainingChars to ""
         else
            set _remainingChars to characters 2 thru -1 of _string
         end if
         
         set _prvDlmt to AppleScript's text item delimiters
         set AppleScript's text item delimiters to ""
         set _string to _firstChar & _remainingChars as string
         set AppleScript's text item delimiters to _prvDlmt
         
         return _string
         
      end uppercaseFirstChar
      
      on uppercaseSecondChar(_string)
         if (count of characters in _string) < 2 then return _string
         
         if pCONVERT_REST_TO_LOWERCASE then set _string to lowercase(_string)
         
         set _firstChar to character 1 of _string
         set _secondChar to uppercase(character 2 of _string)
         
         if (count of characters in _string) < 3 then
            set _remainingChars to ""
         else
            set _remainingChars to characters 3 thru -1 of _string
         end if
         
         set _prvDlmt to AppleScript's text item delimiters
         set AppleScript's text item delimiters to ""
         set _string to _firstChar & _secondChar & _remainingChars as string
         set AppleScript's text item delimiters to _prvDlmt
         
         return _string
      end uppercaseSecondChar
      
      on containsInsideDot(_string)
         if _string contains "." and character -1 of _string is not "." then
            return true
         else
            return false
         end if
      end containsInsideDot
      
      on isEmailAddress(_string)
         if _string contains "@" and _string contains "." then
            return true
         else
            return false
         end if
      end isEmailAddress
      
      on isProtocol(_string)
         if _string contains "://" then
            return true
         else
            return false
         end if
      end isProtocol
      
      on isAbbreviation(_string)
         set _letters to {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
         
         try
            if character 1 of _string is in _letters and character 2 of _string is "." and character 3 of _string is in _letters and character 4 of _string is "." then return true
         end try
         return false
      end isAbbreviation
      
      on isRomanNumeral(_string)
         set _romanNumeralSymbols to {"I", "V", "X", "L", "C", "D", "M"}
         set _chars to characters of _string
         
         repeat with _i from 1 to count of characters of _string
            if character _i of _string is not in _romanNumeralSymbols then return false
         end repeat
         
         return true
      end isRomanNumeral
      
      on specialWord(_string)
         ignoring case
            repeat with _i from 1 to count of pSPECIAL_WORDS
               if item _i of pSPECIAL_WORDS is _string then exit repeat
            end repeat
            
         end ignoring
         
         return item _i of pSPECIAL_WORDS
      end specialWord
      
      on uppercase(_string)
         set _lowercaseCharacters to pLOWERCASE_CHARACTERS & (ASCII character 167)
         set _uppercaseCharacters to pUPPERCASE_CHARACTERS & "SS"
         
         set _prvDlmt to AppleScript's text item delimiters
         
         -- Loop through every lower case character
         repeat with _i from 1 to count of _lowercaseCharacters
            considering case
               if _string contains (item _i of _lowercaseCharacters) then
                  -- Delimit string by lower case character
                  set AppleScript's text item delimiters to (item _i of _lowercaseCharacters)
                  set _stringItems to text items of _string
                  -- Join list by upper case character
                  set AppleScript's text item delimiters to (item _i of _uppercaseCharacters)
                  set _string to _stringItems as string
               end if
            end considering
         end repeat
         
         set AppleScript's text item delimiters to _prvDlmt
         
         return _string
      end uppercase
      
      on lowercase(_string)
         set _lowercaseCharacters to pLOWERCASE_CHARACTERS
         set _uppercaseCharacters to pUPPERCASE_CHARACTERS
         
         set _prvDlmt to AppleScript's text item delimiters
         
         -- Loop through every upper case character
         repeat with _i from 1 to count of _uppercaseCharacters
            considering case
               if _string contains (item _i of _uppercaseCharacters) then
                  -- Delimit string by upper case character
                  set AppleScript's text item delimiters to (item _i of _uppercaseCharacters)
                  set _stringItems to text items of _string
                  -- Join list by lower case character
                  set AppleScript's text item delimiters to (item _i of _lowercaseCharacters)
                  set _string to _stringItems as string
               end if
            end considering
         end repeat
         
         set AppleScript's text item delimiters to _prvDlmt
         
         return _string
      end lowercase
      
      on searchAndReplace(_string, _search, _replace)
         
         if _string does not contain _search then return _string
         
         set _prvDlmt to AppleScript's text item delimiters
         try
            set AppleScript's text item delimiters to _search
            set _stringItems to text items of _string
            set AppleScript's text item delimiters to _replace
            set _string to _stringItems as string
         end try
         set AppleScript's text item delimiters to _prvDlmt
         
         return _string
         
      end searchAndReplace
      
      on paddedString(_string, _padding, _length)
         
         repeat _length - (count of _string) times
            set _string to _padding & _string
         end repeat
         
         return _string
         
      end paddedString
      
   end script
   
   tell TitleCase_Extras to init()
   
   -- Protect special phrases from being parsed
   tell TitleCase_Extras to set _string to protectSpecialPhrases(_string)
   
   -- Convert string to list of words
   set _prvDlmt to AppleScript's text item delimiters
   set AppleScript's text item delimiters to " "
   set _stringItems to text items of _string
   set AppleScript's text item delimiters to _prvDlmt
   
   set _convertedStringItems to {}
   set _previousString to false
   
   repeat with _i from 1 to count of _stringItems
      try
         set _nextString to item (_i + 1) of _stringItems
      on error
         set _nextString to false
      end try
      tell TitleCase_Extras to set end of _convertedStringItems to process(item _i of _stringItems, _previousString, _nextString)
      set _previousString to item _i of _stringItems
   end repeat
   
   -- Convert list of words to string
   set _prvDlmt to AppleScript's text item delimiters
   set AppleScript's text item delimiters to " "
   set _convertedString to _convertedStringItems as string
   set AppleScript's text item delimiters to _prvDlmt
   
   -- Restore special phrases
   tell TitleCase_Extras to set _convertedString to restoreSpecialPhrases(_convertedString)
   
   return _convertedString
end titlecase