-- @Version 1.1.2 -- @Author Luke Wigley -- @Description ---------------------------------------- -- Class for Lingo-based functions for manipulating strings. Not optimised for speed, so best suited for short text. -- For greater speed and more flexibility, consider using a dedicated Xtra (pregEx from OpenXtras.org or Text Xtra -- from UpdateStage. -- -- Note: -- "Words" are defined as containing only letters, numbers and the underscore. Any other characters are -- treated as 'breaking' characters (eg. "Hi_2" => is one word; "Hi-2" is two words "Hi", and "2") -- -- Note: -- you can specify each a string or a list with the Replace and Utility functions. If a list is specified, then -- the relevant function is applied to each item in the list. If a string is specified, a new string is returned. -- @History ---------------------------------------- -- v1.1.2 -- Added GetCharCode() method for getting platform specific char codes -- v1.1.1 -- Changed the explode function so it works when the delimiter > 1 char long -- v1.1.0 -- Added some utility methos (explode, implode, trim etc) -- v1.0.0 -- First version ---------------------------------------- -- static class props property myNonBreakChars property myWhiteSpace property myUpperAlphabet property myLowerAlphabet property myASCIIMap on new (me) me.script._Initialise() return me.script end -- REPLACE on Replace (me, LookIn, ForStr, replaceWith, wordsOnly) -- This functions replaces all occurrances of the 'forStr' in the "LookIn" -- string. Can specify whether the only replace whole words only. -- * LookIn is either a string or a list (if a list, will perform the replace on all items in the list) -- * ForStr is the string to look for -- * replaceWith is the replacement -- * wordsOnly - if true, only replace whole words if ListP(LookIn) then repeat with i = 1 to LookIn.count LookIn[i] = me.Replace(LookIn[i], ForStr, replaceWith, wordsOnly) end repeat else output = "" mx = LookIn.length if wordsOnly then fnd = me.FindWords(LookIn, ForStr) else fnd = me.FindChunks(LookIn, ForStr) end if numFnd = fnd.count if numFnd then p = 1 repeat with aPair in fnd if aPair[1] > p then output = output & LookIn.char[p..aPair[1]-1] end if output = output & replaceWith p = aPair[2] + 1 end repeat if p <= mx then output = output & LookIn.char[p..mx] end if return output else return LookIn end if end if end -- FIND -- The find functions return a list of words that match the search criteria. -- The 'words' in the return list are defined by their start and end chars. -- ie the return list is in the form [[startChar, endchar], [startChar, endchar] ..] on Find (me, LookIn, ForStr, wordsOnly) -- just an alias for FindWords() and FindChunks() if wordsOnly then return me.FindWords(LookIn, ForStr) else return me.FindChunks(LookIn, ForStr) end on FindWords (me, LookIn, ForStr) -- This functions return a list of words that match the search criteria. -- The 'words' in the return list are defined by their start and end chars. -- ie the return list is in the form [[startChar, endchar], [startChar, endchar] ..] if ForStr = EMPTY then return [] returnList = [] lastChar = 0 repeat while true startChar = offset(ForStr, LookIn) if startChar > 0 then firstChar = startChar + lastChar lastChar = firstChar + ForStr.length - 1 -- only add if not joined to another word ok = 1 if startChar > 1 then testchar = LookIn.char[startChar-1] if myNonBreakChars.getOne(testchar) then ok = 0 end if if ok then rightChar = startChar + ForStr.length if rightChar < LookIn.length then testchar = LookIn.char[rightChar] if myNonBreakChars.getOne(testchar) then ok = 0 end if if ok then returnList.append([firstChar, lastChar]) end if -- contine to search the remainder nextStart = startChar + ForStr.length if nextStart < LookIn.length then LookIn = LookIn.char[nextStart..LookIn.length] else return returnList else return returnList end if end repeat end on FindWordsContaining (me, LookIn, ForStr) -- This functions return a list of words contain the specified string. -- The 'words' in the return list are defined by their start and end chars. -- ie the return list is in the form [[startChar, endchar], [startChar, endchar] ..] if ForStr = EMPTY then return [] returnList = [] lastChar = 0 repeat while true startChar = offset(ForStr, LookIn) if startChar > 0 then -- go left looking for break repeat while startChar > 1 testchar = LookIn.char[startChar-1] if NOT myNonBreakChars.getOne(testchar) then exit repeat else startChar = startChar -1 end if end repeat -- go right looking for break endChar = startChar + ForStr.length - 1 repeat while endChar < LookIn.length testchar = LookIn.char[endChar + 1] if NOT myNonBreakChars.getOne(testchar) then exit repeat else endChar = endChar + 1 end if end repeat firstChar = startChar + lastChar lastChar = endChar + lastChar returnList.append([firstChar, lastChar]) -- contine to search the remainder nextStart = endChar + 1 if nextStart < LookIn.length then LookIn = LookIn.char[nextStart..LookIn.length] else return returnList else return returnList end if end repeat end on FindWordsStarting (me, LookIn, ForStr) -- This functions return a list of words that start with the specified string. -- The 'words' in the return list are defined by their start and end chars. -- ie the return list is in the form [[startChar, endchar], [startChar, endchar] ..] if ForStr = EMPTY then return [] returnList = [] lastChar = 0 repeat while true startChar = offset(ForStr, LookIn) if startChar > 0 then -- go left looking for break ok = 1 if startChar > 1 then testchar = LookIn.char[startChar-1] if (myNonBreakChars.getOne(testchar)) then ok = 0 end if if ok then -- go right looking for break endChar = startChar + ForStr.length - 1 repeat while endChar < LookIn.length testchar = LookIn.char[endChar + 1] if NOT myNonBreakChars.getOne(testchar) then exit repeat else endChar = endChar + 1 end if end repeat firstChar = startChar + lastChar lastChar = endChar + lastChar returnList.append([firstChar, lastChar]) else firstChar = startChar + lastChar lastChar = firstChar + ForStr.length - 1 endChar = startChar + ForStr.length - 1 end if -- contine to search the remainder nextStart = endChar + 1 if nextStart < LookIn.length then LookIn = LookIn.char[nextStart..LookIn.length] else return returnList else return returnList end if end repeat end on FindChunks (me, LookIn, ForStr) -- This functions return a list of start and end chars for the occurances of the chunk if ForStr = EMPTY then return [] returnList = [] lastChar = 0 repeat while true startChar = offset(ForStr, LookIn) if startChar > 0 then firstChar = startChar + lastChar lastChar = firstChar + ForStr.length - 1 returnList.append([firstChar, lastChar]) -- continue to search the remainder nextStart = startChar + ForStr.length if nextStart < LookIn.length then LookIn = LookIn.char[nextStart..LookIn.length] else return returnList else return returnList end if end repeat end -- UTILITY FUNCTIONS on Explode (me, aSeparator, aString) -- converts the string into a list, splitting the string -- using the supplied delimiter (the "delimiter" can be more -- that one-char long) if aSeparator.ilk <> #String then aSeparator = RETURN if aString.ilk <> #String then return [] rList = [] delLength=length(aSeparator) if delLength = 0 then return [aString] end if mx = aString.length if mx = 0 then return [] else p = offset(aSeparator, aString) repeat while p subStr = aString.char[1..p] delete the last char of subStr rList.add(subStr) aString = aString.char[p + delLength..length(aString)] p = offset(aSeparator, aString) end repeat rList.add(aString.char[1..length(aString)]) return rList end if end on Implode (me, glue, aList) -- Joins the list into a string, using the 'glue' as a separator if glue.ilk <> #string then glue = "" if aList.ilk <> #list then return "" mx = aList.count - 1 if mx < 0 then return "" rStr = "" repeat with i = 1 to mx if aList[i].ilk = #List then rStr = rStr & me.Implode(glue, aList[i]) & glue else rStr = rStr & aList[i] & glue end repeat if aList[aList.count].ilk = #List then rStr = rStr & me.Implode(glue, aList[i]) else rStr = rStr & aList[aList.count] return rStr end on ToUpper (me, aString) -- Converts a String to Uppercase if ListP(aString) then repeat with i = 1 to aString.count aString[i] = me.ToUpper(aString[i]) end repeat else if aString.ilk <> #string then aString = string(aString) mx = aString.length repeat with a = 1 to mx c = offset(aString.char[a],myUpperAlphabet) if c > 0 then put char c of myUpperAlphabet into char a of aString end repeat end if return aString end on ToLower (me, aString) -- Converts a string to lower if ListP(aString) then repeat with i = 1 to aString.count aString[i] = me.ToLower(aString[i]) end repeat else if aString.ilk <> #string then aString = string(aString) mx = aString.length repeat with a = 1 to mx c = offset(char a of aString,myLowerAlphabet) if c > 0 then put char c of myLowerAlphabet into char a of aString end repeat return aString end if end on Trim (me, aString) -- Trims the white space from the start and end of a string. If a list is -- specified, rather than a string, then each item in the list is trimmed. -- * returns a new string, or VOID if a list was passed in (the change is made to the list) if ListP(aString) then repeat with i = 1 to aString.count aString[i] = me.Trim(aString[i]) end repeat else if aString.ilk <> #string then aString = string(aString) return (me.LTrim(me.RTrim(aString))) end if end on LTrim (me, aString) -- Trims the white space from the start of a string. If a list is -- specified, rather than a string, then each item in the list is trimmed. -- * returns a new string, or VOID if a list was passed in (the change is made to the list) if ListP(aString) then repeat with i = 1 to aString.count aString[i] = me.LTrim(aString[i]) end repeat else if aString.ilk <> #string then aString = string(aString) repeat while myWhiteSpace.getPos(aString.char[1]) delete char 1 of aString end repeat return aString end if end on RTrim (me, aString) -- trims the white space from the end of a string. If a list is -- specified, rather than a string, then each item in the list is trimmed. -- * returns a new string, or VOID if a list was passed in (the change is made to the list) if ListP(aString) then repeat with i = 1 to aString.count aString[i] = me.RTrim(aString[i]) end repeat else if aString.ilk <> #string then aString = string(aString) repeat while myWhiteSpace.getPos(the last char of aString) delete the last char of aString end repeat return aString end if end on ConvertToPC(me, aString) -- Maps the high-ASCII characters from Mac format to PC format -- (adapted from the MU behaviours that shipped with D7) if ListP(aString) then repeat with i = 1 to aString.count aString[i] = me.ConvertToPC(aString[i]) end repeat else pcString = "" i = aString.char.count repeat while i aChar = aString.char[i] charNum = charToNum(aChar) if charNum > 127 then -- and charNum < 256 then aChar = numToChar(myASCIIMap[charNum - 127]) end if pcString = aChar & pcString i = i - 1 end repeat return pcString end if end on GetCharCode (me, charNum, ToFormat) case (toFormat) of #PC: if charNum > 127 then -- and charNum < 256 then return (myASCIIMap[charNum - 127]) end if #Mac: if charNum > 127 and charNum < 256 then return (127 + myASCIIMap.getPos(charNum)) end if end case return charNum end on ConvertToMac(me, aString) -- Maps the high-ASCII characters from PC format to MAC format -- (adapted from the MU behaviours that shipped with D7) if ListP(aString) then repeat with i = 1 to aString.count aString[i] = me.ConvertToMac(aString[i]) end repeat else macString = "" i = aString.char.count repeat while i aChar = aString.char[i] charNum = charToNum(aChar) if charNum > 127 and charNum < 256 then aChar = numToChar(127 + myASCIIMap.getPos(charNum)) end if macString = aChar & macString i = i - 1 end repeat return macString end if end -- PRIVATE on _Initialise(me) if myNonBreakChars.ilk <> #List then put "Initialising LingoTextUtil" -- 'breakchars' break chunks into 'words' myNonBreakChars = [] repeat with i = 65 to 90 myNonBreakChars.append(numToChar(i)) -- uppercase letter myNonBreakChars.append(numToChar(i+32)) -- lowercase letter end repeat repeat with i = 48 to 57 myNonBreakChars.append(numToChar(i)) -- numbers end repeat myNonBreakChars.append("_") -- white space myWhiteSpace = [SPACE,TAB,NumToChar(10),NumToChar(13)] myUpperAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" myLowerAlphabet = "abcdefghijklmnopqrstuvwxyz" -- ascii map myASCIIMap = [ \ 196, 197, 199, 201, 209, 214, 220, 225, 224, 226, 228, 227, 229, \ 231, 233, 232, 234, 235, 237, 236, 238, 239, 241, 243, 242, 244, \ 246, 245, 250, 249, 251, 252, 134, 176, 162, 163, 167, 149, 182, \ 223, 174, 169, 153, 180, 168, 141, 198, 216, 144, 177, 143, 142, \ 165, 181, 240, 221, 222, 254, 138, 170, 186, 253, 230, 248, 191, \ 161, 172, 175, 131, 188, 208, 171, 187, 133, 160, 192, 195, 213, \ 140, 156, 173, 151, 147, 148, 145, 146, 247, 215, 255, 159, 158, \ 164, 139, 155, 128, 129, 135, 183, 130, 132, 137, 194, 202, 193, \ 203, 200, 205, 206, 207, 204, 211, 212, 157, 210, 218, 219, 217, \ 166, 136, 152, 150, 154, 178, 190, 184, 189, 179, 185] end if end