Manipulating Numbers
Working with and manipulating numbers is an important and regular occurrence in scripting. Basic mathematic operations—such as addition, subtraction, multiplication, and division—are language-level features, but some other commonly performed operations require custom scripting.
Converting a Number to a String
Scripts often need to convert numbers to string format to display information to the user or populate a document. In AppleScript, this conversion can be accomplished most of the time simply by using the coercion operator as
, as shown in Listing 20-1.
APPLESCRIPT
12 as string
--> Result: "12"
In JavaScript, the same conversion can be accomplished by calling the toString()
method, as shown in Listing 20-2.
JAVASCRIPT
num = 12
num.toString()
// Result: "12"
Converting a Long Number to a String
In AppleScript, long numeric values are displayed in scientific notation. For example, 1234000000
is displayed by a script as 1.234E+9
. When this value is coerced to a string, it becomes: "1.234E+9"
. The handler in Listing 20-3 converts a number, regardless of length, to a string of numeric characters instead of a numeric string in scientific notation.
APPLESCRIPT
on convertNumberToString(theNumber)
set theNumberString to theNumber as string
set theOffset to offset of "E" in theNumberString
if theOffset = 0 then return theNumberString
set thePrefix to text 1 thru (theOffset - 1) of theNumberString
set theConvertedNumberPrefix to ""
if thePrefix begins with "-" then
set theConvertedNumberPrefix to "-"
if thePrefix = "-" then
set thePrefix to ""
else
set thePrefix to text 2 thru -1 of thePrefix
end if
end if
set theDecimalAdjustment to (text (theOffset + 1) thru -1 of theNumberString) as number
set isNegativeDecimalAdjustment to theDecimalAdjustment is less than 0
if isNegativeDecimalAdjustment then
set thePrefix to (reverse of (characters of thePrefix)) as string
set theDecimalAdjustment to -theDecimalAdjustment
end if
set theDecimalOffset to offset of "." in thePrefix
if theDecimalOffset = 0 then
set theFirstPart to ""
else
set theFirstPart to text 1 thru (theDecimalOffset - 1) of thePrefix
end if
set theSecondPart to text (theDecimalOffset + 1) thru -1 of thePrefix
set theConvertedNumber to theFirstPart
set theRepeatCount to theDecimalAdjustment
if (length of theSecondPart) is greater than theRepeatCount then set theRepeatCount to length of theSecondPart
repeat with a from 1 to theRepeatCount
try
set theConvertedNumber to theConvertedNumber & character a of theSecondPart
on error
set theConvertedNumber to theConvertedNumber & "0"
end try
if a = theDecimalAdjustment and a is not equal to (length of theSecondPart) then set theConvertedNumber to theConvertedNumber & "."
end repeat if theConvertedNumber ends with "." then set theConvertedNumber to theConvertedNumber & "0"
if isNegativeDecimalAdjustment then set theConvertedNumber to (reverse of (characters of theConvertedNumber)) as string
return theConvertedNumberPrefix & theConvertedNumber
end convertNumberToString
Listing 20-3 shows how to call the handler in Listing 20-3.
APPLESCRIPT
convertNumberToString(8.72124243234E+11)
--> Result: "872124243234"
Adding a Descriptive Suffix to a Number
The handlers Listing 20-5 and Listing 20-6 convert a number to a string and appends a suffix of "st"
, "nd"
, "rd"
, or "th"
, resulting in strings such as "1st"
, "2nd"
, "3rd"
, and "4th"
.
APPLESCRIPT
on addDescriptiveSuffixToNumber(theNumber)
-- Determine the suffix to add, based on the last two digits
set theLastDigit to theNumber mod 10
set theLastTwoDigits to theNumber mod 100
set theSuffix to "th"
if {1, -1} contains theLastDigit and {11, -11} does not contain theLastTwoDigits then
set theSuffix to "st"
else if {2, -2} contains theLastDigit and {12, -12} does not contain theLastTwoDigits then
set theSuffix to "nd"
else if {3, -3} contains theLastDigit and {13, -13} does not contain theLastTwoDigits then
set theSuffix to "rd"
end if
-- Return the number and suffix
return (theNumber as string) & theSuffix
end addDescriptiveSuffixToNumber
JAVASCRIPT
function addDescriptiveSuffixToNumber(num) {
// Convert the number to absolute value
var integer = Math.abs(num)
// Determine the suffix to add, based on the last two digits
var suffix = "th"
var lastDigit = integer % 10
var lastTwoDigits = integer % 100
if (lastDigit === 1 && lastTwoDigits !== 11) {
suffix = "st"
}
else if (lastDigit === 2 && lastTwoDigits !== 12) {
suffix = "nd"
}
else if (lastDigit === 3 && lastTwoDigits !== 13) {
suffix = "rd"
}
// Return the number and suffix
return num.toString() + suffix
}
Listing 20-7 and Listing 20-8 show how to test the handlers in Listing 20-5 and Listing 20-6 by looping through a range of positive and negative numbers.
APPLESCRIPT
set theTestResults to ""
repeat with a from -10 to 10
set theTestResults to theTestResults & addDescriptiveSuffixToNumber(a)
if a is less than 10 then set theTestResults to theTestResults & ", "
end repeat
theTestResults
--> Result: "-10th, -9th, -8th, -7th, -6th, -5th, -4th, -3rd, -2nd, -1st, 0, 1st, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th"
JAVASCRIPT
var testResults = ""
for (var i = -10; i <= 10; i++) {
testResults += addDescriptiveSuffixToNumber(i)
if (i < 10) {
testResults += ", "
}
}
testResults
// Result: "-10th, -9th, -8th, -7th, -6th, -5th, -4th, -3rd, -2nd, -1st, 0th, 1st, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th"
Listing 20-9 and Listing 20-10 show how to call the handlers in Listing 20-5 and Listing 20-6 to identify positions of items in a list.
APPLESCRIPT
set thePersonList to {"Sal", "Ben", "Chris", "David"}
set theListLength to length of thePersonList
repeat with a from 1 to theListLength
set theSuffixedNumber to addDescriptiveSuffixToNumber(a)
set thePerson to item a of thePersonList
display dialog "The " & theSuffixedNumber & " person in list is " & thePerson & "."
end repeat
JAVASCRIPT
var app = Application.currentApplication()
app.includeStandardAdditions = true
var personList = ["Sal", "Ben", "Chris", "David"]
var listLength = personList.length
for (var i = 0; i < listLength; i++) {
var suffixedNum = addDescriptiveSuffixToNumber(i + 1)
var person = personList[i]
app.displayDialog(`The ${suffixedNum} person in list is ${person}.`)
}
Adding Leading Zeros to a Number
The handlers in Listing 20-11 and Listing 20-12 convert a number to a string and prepends it with leading zeros until it reaches a certain length. They accept two parameters—the number to add leading zeros to and the maximum number of leading zeros to add. For example, if the maximum number of leading zeros is set to 2
, the results range from 001
to 999
. If the maximum number of leading zeros is 3
, the results range from 0001
to 9999
, and so on.
APPLESCRIPT
on addLeadingZerosToNumber(theNumber, theMaxLeadingZeroCount)
-- Determine if the number is negative
set isNegative to theNumber is less than 0
-- Determine when the maximum number of digits will be reached
set theThreshold to (10 ^ theMaxLeadingZeroCount) as integer
-- If the number is shorter than the maximum number of digits
if theNumber is less than theThreshold then
-- If the number is negative, convert it to positive
if isNegative = true then set theNumber to -theNumber
-- Add the zeros to the number
set theLeadingZeros to ""
set theDigitCount to length of ((theNumber div 1) as string)
set theCharacterCount to (theMaxLeadingZeroCount + 1) - theDigitCount
repeat theCharacterCount times
set theLeadingZeros to (theLeadingZeros & "0") as string
end repeat
-- Make the number negative, if it was previously negative
if isNegative = true then set theLeadingZeros to "-" & theLeadingZeros
-- Return the prefixed number
return (theLeadingZeros & (theNumber as text)) as string
-- If the number is greater than or equal to the maximum number of digits
else
-- Return the original number
return theNumber as text
end if
end addLeadingZerosToNumber
JAVASCRIPT
function addLeadingZerosToNumber(num, maxLeadingZeroCount) {
var leadingZeros = ""
// Convert the number to absolute value
var absNum = Math.abs(num)
// Determine when the maximum number of digits will be reached
var threshold = Math.pow(10, maxLeadingZeroCount)
// If the number is shorter than the maximum number of digits
if (absNum < threshold) {
// Prepare a leading zeros string
var digitCount = Math.trunc(absNum).toString().length
var charCount = maxLeadingZeroCount + 1 - digitCount
for (var i = 0 ; i < charCount; i++) {
leadingZeros += "0"
}
}
// Add the zeros to the number
var result = `${leadingZeros}${absNum}`
// Make the number negative, if it was previously negative
if (num < 0) {
result = `-${result}`
}
// Return the prefixed number
return result
}
Listing 20-13 and Listing 20-14 show how to call the handlers in Listing 20-11 and Listing 20-12.
APPLESCRIPT
addLeadingZerosToNumber(9, 3)
--> Result: "0009"
JAVASCRIPT
addLeadingZerosToNumber(9, 3)
// Result: "0009"
Comma-Delimiting a Number
The handlers Listing 20-15 and Listing 20-16 comma-delimit a numeric value and converts it to a string.
APPLESCRIPT
on convertNumberToCommaDelimitedString(theNumber)
-- Convert the number to a string
set theNumber to convertNumberToString(theNumber)
-- Determine the length of the number
set theNumberLength to length of theNumber
-- Reverse the number so a comma can be added every 3 digits
set theNumber to (reverse of every character of theNumber) as string
-- Loop through the number's digits, add commas, and put the numbers back in the correct order
set theConvertedNumber to ""
repeat with a from 1 to theNumberLength
if a is theNumberLength or (a mod 3) is not 0 then
set theConvertedNumber to (character a of theNumber & theConvertedNumber) as string
else
set theConvertedNumber to ("," & character a of theNumber & theConvertedNumber) as string
end if
end repeat
-- Return the comma delimited number
return theConvertedNumber
end convertNumberToCommaDelimitedString
JAVASCRIPT
function convertNumberToCommaDelimitedString(num) {
// Convert the number to a string
var numString = num.toString()
if (numString.indexOf("e") != - 1) {
numString = convertNumberToString(numString)
}
// Reverse the number so a comma can be added every 3 digits
numString = numString.split("").reverse().join("")
var numStringWithCommas = ""
// Determine the length of the number
var numStringLength = numString.length
// Loop through the number's digits, add commas, and put the numbers back in the correct order
for (var i = 0; i < numStringLength; i++) {
var toPrepend = numString[i]
if (i != numStringLength - 1 && ((i + 1) % 3) == 0) {
toPrepend = "," + toPrepend
}
numStringWithCommas = toPrepend + numStringWithCommas
}
// Return the comma delimited number
return numStringWithCommas
}
Listing 20-17 and Listing 20-18 shows how to call the handlers in Listing 20-15 and Listing 20-16.
APPLESCRIPT
convertNumberToCommaDelimitedString(872124243234)
--> Result: "872,124,243,234"
JAVASCRIPT
convertNumberToCommaDelimitedString(872124243234)
// Result: "872,124,243,234"
Determining if a Number is an Odd Number
The handlers in Listing 20-28 and Listing 20-29 determine whether a whole number is even or odd. A returned value of false
indicates the passed number is even; a returned value of true
indicates the passed number is odd.
APPLESCRIPT
on isNumberOdd(theNumber)
if theNumber mod 2 is not 0 then
return true
else
return false
end if
end isNumberOdd
JAVASCRIPT
function isNumberOdd(num) {
return num % 2 !== 0
}
Listing 20-30 and Listing 20-31 show how to call the handlers in Listing 20-28 and Listing 20-29.
APPLESCRIPT
isNumberOdd(3)
--> Result: true
JAVASCRIPT
isNumberOdd(3)
// Result: true
Listing 20-32 and Listing 20-33 show how to call the handlers in Listing 20-28 and Listing 20-29 by prompting the user to enter an even number.
APPLESCRIPT
repeat
display dialog "Enter an even integer:" default answer ""
try
if text returned of result is not "" then set theNumberProvided to text returned of result as integer
if isNumberOdd(theNumberProvided) is false then exit repeat
end try
end repeat
JAVASCRIPT
var app = Application.currentApplication()
app.includeStandardAdditions = true
while (true) {
var result = app.displayDialog("Enter an even integer:", {defaultAnswer: ""})
var text = result.textReturned
if (text !== "") {
var num = Number(text)
if (!isNumberOdd(num)) {
break
}
}
}
Rounding and Truncating a Number
The handlers in Listing 20-34 and Listing 20-35 round and truncate a numeric value, and convert it to a string. Provide a numeric value and indicate a number of decimal places.
APPLESCRIPT
on roundAndTruncateNumber(theNumber, numberOfDecimalPlaces)
if numberOfDecimalPlaces is 0 then
set theNumber to theNumber + 0.5
return convertNumberToString(theNumber div 1)
end if
set theRoundingValue to "5"
repeat numberOfDecimalPlaces times
set theRoundingValue to "0" & theRoundingValue
end repeat
set theRoundingValue to ("." & theRoundingValue) as number
set theNumber to theNumber + theRoundingValue
set theModValue to "1"
repeat numberOfDecimalPlaces - 1 times
set theModValue to "0" & theModValue
end repeat
set theModValue to ("." & theModValue) as number
set theSecondPart to (theNumber mod 1) div theModValue
if length of (theSecondPart as text) is less than numberOfDecimalPlaces then
repeat numberOfDecimalPlaces - (the length of (theSecondPart as text)) times
set theSecondPart to ("0" & theSecondPart) as string
end repeat
end if
set theFirstPart to theNumber div 1
set theFirstPart to convertNumberToString(theFirstPart)
set theNumber to (theFirstPart & "." & theSecondPart)
return theNumber
end roundAndTruncateNumber
JAVASCRIPT
function roundAndTruncateNumber(num, numDecimalPlaces) {
if (numDecimalPlaces === 0) {
num = num + 0.5
return convertNumberToString(num / 1)
}
var roundingValue = "5"
for (var i = 0; i < numDecimalPlaces; i++) {
roundingValue = "0" + roundingValue
}
roundingValue = Number("0." + roundingValue)
num += roundingValue
var modValue = "1"
for (var i = 0; i < numDecimalPlaces - 1; i++) {
modValue = "0" + modValue
}
modValue = Number("0." + modValue)
var secondPart = Math.floor((num % 1) / modValue)
var secondPartStringLength = secondPart.toString().length
if (secondPartStringLength < numDecimalPlaces) {
var count = numDecimalPlaces - secondPartStringLength
for (var i = 0; i < count; i++) {
secondPart = "0" + secondPart
}
}
var firstPart = Math.floor(num)
firstPart = convertNumberToString(firstPart)
return `${firstPart}.${secondPart}`
}
Listing 20-36 shows how to call the handler in Listing 20-34.
APPLESCRIPT
roundAndTruncateNumber(1.04575, 3)
--> Result: "1.046"
Copyright © 2018 Apple Inc. All rights reserved. Terms of Use | Privacy Policy | Updated: 2016-06-13