Converting Lower case to Upper Case

Hi,

alternative you can install the Satimage Scripting Additions
which provide lowercase and uppercase commands

this keeps it all in the script


set foo to "foo"
set foo to do shellscript "echo " & foo & " | tr a-z A-Z"

I will use this in lots of places

Cheers, been a great help.

Here’s a subroutine which does the same. I got this code from this forum, unfortunately I forget who wrote it. Anyway, I tested the speed of this approach versus the do shell script approach using the “GetMilliSec subroutine and the Lotsa method”. Here’s the results.

Each test was run 500 times
the string I used in the test was “make this upper case.”
do shellscript “echo " & theString & " | tr a-z A-Z” → 11.368 secs
makeCaseUpper(theString) → 0.894 secs
Results: the subroutine is about 13 times faster than the do shell script command.


on makeCaseUpper(theString)
	set UPPERCASE to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	set lowercase to "abcdefghijklmnopqrstuvwxyz"
	set AppleScript's text item delimiters to " "
	set theWords to text items of theString as list
	set AppleScript's text item delimiters to ""
	set newList to {}
	repeat with theWord in theWords
		set chrs to characters of theWord
		set Nchrs to count chrs -- get the number of characters
		repeat with K from 1 to Nchrs
			if (item K of chrs) is in lowercase then
				set olc to offset of (item K of chrs) in lowercase
				set item K of chrs to character olc of UPPERCASE
			end if
		end repeat
		set end of newList to chrs as string
	end repeat
	set AppleScript's text item delimiters to " "
	set theString to newList as string
	set AppleScript's text item delimiters to ""
	return theString
end makeCaseUpper

See also: Change Text Case

Hi regulus,

the Scripting Addition mentioned above is 25 times faster than the do shell script command :wink:

You could also do something like this:

on ToggleCase(theString)
	set theString to ASCII number of theString
	if theString ≥ 65 and theString ≤ 90 then set theString to ASCII character of (theString + 32)
	if theString ≥ 97 and theString ≤ 122 then set theString to ASCII character of (theString - 32)
	return theString
end ToggleCase

Not sure if it is faster than the other option, would be interesting to see some time tests.


on my Dual G5 at work it this script takes about 8 seconds to loop 10,000 times

on ToggleCase(theString)
	set theString to ASCII number of theString
	if theString ≥ 65 and theString ≤ 90 then set theString to ASCII character of (theString + 32)
	return theString
end ToggleCase

set x to current date
set p to "make this upper case."
repeat with i from 1 to 10000
	repeat with q from 1 to count of characters of p
		set z to ToggleCase(character q of p)
	end repeat
end repeat
set y to current date
set y to y - x

Interesting idea Jerome. I made a few changes to your code toget it to change the case to UPPER as this discussion requests. Here’s what I came up with.


set theString to "make this upper case"

set chrs to characters of theString
set toggleList to {}
repeat with i from 1 to (count of chrs)
	my caseUPPER(item i of chrs)
	set end of toggleList to result
end repeat
set toggleString to toggleList as string

on caseUPPER(chr)
	set asciiNum to ASCII number of chr
	if asciiNum ≥ 97 and asciiNum ≤ 122 then set chr to ASCII character of (asciiNum - 32)
	return chr
end caseUPPER

So I ran the “GetMilliSec subroutine and the Lotsa method” again on this modified method and the one I posted earlier.

Each test was run 500 times
the string I used in the test was “make this upper case.”
Jerome’s modified method → 0.719 secs
my makeCaseUpper(theString) → 0.875 secs
Results: Jerome’s modified method is about 20% faster than my subroutine.

Cool idea Jerome!

Hi,

Your comparison testing is wrong. One script uses ‘do shell script’ while the other one doesn’t. If the user has to use the do shell script and change to uppercase instead of piping the output to ‘tr’, then what are the times?

gl,

For this particular problem, yet another approach using offsets (slim 15% advantage over Regulus’, didn’t test the others):

makeCaseUpper("Now is the time, perhaps, for all good men")
on makeCaseUpper(theString)
	set UC to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	set LC to "abcdefghijklmnopqrstuvwxyz"
	set C to characters of theString
	repeat with ch in C
		if ch is in LC then set contents of ch to item (offset of ch in LC) of UC
	end repeat
	return C as string
end makeCaseUpper

kel, I’m not sure what you mean? Piping the output to tr changes to upper case and uses the “do shell script” command. Which 2 comparisons do you mean?

Hi regulus,

What I mean is that the op wanted to convert shell output to uppercase. The call to the shell takes time, so you have to include that in the comparison. I use Jon’s Commands’ ‘the ticks’ in these:

Script 1 (pipe output to ‘tr’:


set t1 to the ticks
set t to do shell script "echo hello | tr '[:lower:]' '[:upper:]'"
set t2 to the ticks
display dialog (t2 - t1)
t

Script 2 (convert output to all uppercase with AppleScript):


set t1 to the ticks
set t to uppercase (do shell script "echo hello")
set t2 to the ticks
display dialog (t2 - t1)
t

gl,

Oh kel, I see what you meant. You wanted me to get the string for my test from the shell, thus comparing TR to my subroutine. My thought was that you could avoid the shell all together with my subroutine whereas with TR you couldn’t… but if you do need the shell to get the string then I see your point.

So here’s the results with the test kel suggested. In these two tests the shell generated the string to be converted to upper case, then that string was sent to either TR or the subroutine. The results were vastly different. I alsoi ncluded the actual code for the test. Note, anyone that wants to run this test needs to first install the GetMilliSec scripting addition… I found it on this website.

– results of 500 tests → {9.645, 7.059, 1.366340841479}
The first result is for piping to TR. it took 9.645 secs
The second reasult is for piping the string to the subroutine → it took 7.059 secs for about a 36% improvement.

So the two conclusions for the subroutine are:

  1. 36% improvement over TR when the shell generates the string
  2. without using the shell to first generate your string you’ll see a 1300% improvement.

set Tests to RunTest() -- this kicks it off
----
on RunTest()
	set lotsa to 500 -- the number of times the test will repeat
	-- Any other preliminary values here.
	
	-- Dummy loop to absorb a small observed time handicap in the first repeat.
	repeat lotsa times -- warming up the engine.
	end repeat
	
	-- Test 1
	set t to GetMilliSec
	repeat lotsa times
		-- test code or handler call here.
		
		do shell script "echo hello | tr '[:lower:]' '[:upper:]'"
		
		-- end of code fragment
	end repeat
	set t1 to ((GetMilliSec) - t) / 1000
	
	-- Test 2
	set t to GetMilliSec
	repeat lotsa times
		-- test code or handler call here.
		
		my makeCaseUpper(do shell script "echo hello")
		
		-- end of code fragment
	end repeat
	set t2 to ((GetMilliSec) - t) / 1000
	-- Timings.
	return {t1, t2, t1 / t2}
end RunTest

on makeCaseUpper(theString)
	set UPPERCASE to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	set lowercase to "abcdefghijklmnopqrstuvwxyz"
	set AppleScript's text item delimiters to " "
	set theWords to text items of theString as list
	set AppleScript's text item delimiters to ""
	set newList to {}
	repeat with theWord in theWords
		set chrs to characters of theWord
		set Nchrs to count chrs -- get the number of characters
		repeat with K from 1 to Nchrs
			if (item K of chrs) is in lowercase then
				set olc to offset of (item K of chrs) in lowercase
				set item K of chrs to character olc of UPPERCASE
			end if
		end repeat
		set end of newList to chrs as string
	end repeat
	set AppleScript's text item delimiters to " "
	set theString to newList as string
	set AppleScript's text item delimiters to ""
	return theString
end makeCaseUpper

Hello

Is there a shell script command allowing the lower <> upper conversion for accented chars which are often used in non-English languages ?

Yvan KOENIG

Hi Yvan,

you could add accented characters manually to ‘tr’:

do shell script “echo ‘french accents: éèê - german umlauts:äöü - spanish characters: ñ …’ | tr [a-zéèêäöüñ] [A-ZÉÈÊÄÖÜÑ]]”

D.

Hi regulus,

Yes, that’s what i meant. I found it interesting also, that Satimage osax’ ‘uppercase’ was about two times faster than piping the output to ‘tr’. I wonder what the times would be if you test it in Terminal. I don’t know how to do that though.

gl,

Python will handle them. Check out the changeCase handler I posted (from the thread I mentioned earlier).

Thanks

I didn’t saw it (don’t lok at page 2)

Adding accented chars in the list by hand was a bit boring :wink:

Yvan KOENIG

I found this nice handler on a website, and I have often found it helpful. (I wish I could take credit.)

on changeCaseOfText(theText, theCaseToSwitchTo)
	if theCaseToSwitchTo contains "lower" then
		set theComparisonCharacters to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		set theSourceCharacters to "abcdefghijklmnopqrstuvwxyz"
	else if theCaseToSwitchTo contains "upper" then
		set theComparisonCharacters to "abcdefghijklmnopqrstuvwxyz"
		set theSourceCharacters to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	else
		return theText
	end if
	set theAlteredText to ""
	repeat with aCharacter in theText
		set theOffset to offset of aCharacter in theComparisonCharacters
		if theOffset is not 0 then
			set theAlteredText to (theAlteredText & character theOffset of theSourceCharacters) as string
		else
			set theAlteredText to (theAlteredText & aCharacter) as string
		end if
	end repeat
	return theAlteredText
end changeCaseOfText

For AppleScriptObjectiveC, i highly recommended ‘RegexAndStuffLib’ vom Shane Stanley. Please look at https://latenightsw.com/freeware/.