Dialog result is integer?

How can I test to be sure that the result from a dialog is an integer? My code example:

			repeat
				set startNumber to (display dialog "Enter a starting number:" default answer "")
				if startNumber is integer then
					exit repeat
				else
					display dialog "The starting number needs to be an integer!" buttons {"Enter again", "Cancel"} default button 1
				end if
			end repeat

Hi buzzwig,

I am using code like follows in my AppleScript projects to ensure that the user really enters an integer:


property mytitle : "Int Value Getter"

set intvalue to my getintvalue()

-- I am asking the user to provide an integer
-- In case the user cancels the dialog, I return «missing value»
on getintvalue()
	set dlgmsg to "Please enter an integer:"
	try
		display dialog dlgmsg default answer "1" buttons {"Cancel", "Enter"} default button 2 with title mytitle
	on error
		-- User canceled
		return missing value
	end try
	set dlgresult to result
	set usrinput to text returned of dlgresult
	-- the user did not enter anything...
	if usrinput is "" then
		my getintvalue()
	else
		-- let's check if the user entered numbers only
		set nums to {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}
		set invalidchars to ""
		repeat with char in usrinput
			if char is not in nums then
				set invalidchars to invalidchars & char & space
			end if
		end repeat
		-- we found invalid characters
		if invalidchars is not "" then
			set errmsg to "We found the following characters in the given input. Please enter numbers only." & return & return & invalidchars & return
			my dsperrmsg(errmsg, "--")
			my getintvalue()
		else
			-- let's try to transform the user input into an integer
			try
				set intvalue to usrinput as integer
				return intvalue
			on error
				set errmsg to "We could not coerce the given input into an integer:" & return & return & usrinput & return
				my dsperrmsg(errmsg, "--")
				my getintvalue()
			end try
		end if
	end if
end getintvalue

-- I am displaying error messages to the user
on dsperrmsg(errmsg, errnum)
	tell me
		activate
		display dialog errmsg & " (" & errnum & ")" buttons {"OK"} default button 1 with title mytitle with icon stop
	end tell
end dsperrmsg

This code evinces several misunderstandings.

  1. display dialog returns a record that contains properties with information about the button that was used to exit the dialog, the text entered (if a default answer is supplied), and whether the dialog timed out (if giving up after is specified).

text returned of startNumber would yield the string value that the user entered.

  1. The is operator is comparing a record object (the result from display dialog) to the integer type object. This will always be false. Even if the object being compared was an integer, the expression would still always yield a false value. 5 is an integer (a member of the type integer), but it is not the same as the abstract idea of integers (which the integer type object represents).

The expression class of startNumber is integer would work as expected, if startNumber had any chance of being an integer (it is always a record in the original script).

  1. You have to specify that you want to convert to an integer the string value that is returned in the record result of display dialog.

(text returned of startNumber) as integer invokes AppleScript’s built-in string to integer coercion. It throws an error if it is unable to convert it to an integer (could not be parsed as an integer, too big to fit in an AppleScript integer object, maybe other reasons).

With probably more error checking than is necessary, here is some code that I think will do what you want:

repeat
	set dialogResult to (display dialog "Enter a starting number:" default answer "")
	try
		set startNumber to (text returned of dialogResult) as integer
		-- This test should be unnecessary, just exiting the loop should be fine.
		if class of startNumber is integer then ¬
			exit repeat
	on error m number n from o partial result r to t
		set unableToConvertToInteger to n is -1700 and o is text returned of dialogResult and t is integer -- e.g. "asdf"
		set numericResultTooLarge to n is -2702 and t is integer -- e.g. anything larger than 2^29-1
		if not (unableToConvertToInteger or numericResultTooLarge) then error m number n from o partial result r to t -- return {m, n, o, r, t} -- to see the error values, use the return instead
	end try
	display dialog "The starting number needs to be a valid integer!" buttons {"Enter again", "Cancel"} default button 1
end repeat
startNumber

Without all the error checking, it could look something like this:

repeat
	set dialogResult to (display dialog "Enter a starting number:" default answer "")
	try
		set startNumber to (text returned of dialogResult) as integer
		exit repeat
	end try
	display dialog "The starting number needs to be a valid integer!" buttons {"Enter again", "Cancel"} default button 1
end repeat
startNumber

Note that this as integer method for converting a string into an integer means that (as examples) “2.5” yields 2, “3.5” yields 4 (rounds “real” values to the nearest even integer), and “2.3e5” yields 230000 (scientific notation). If these results are undesirable you will have check that the string contains only digit characters before trying to coerce it (Martin Michel’s code does this).

Edit: Swapped return and error (previously commented out) in the error handling script.

An alternative would be to try coercing to number. Depending on what was acceptable, you could then either check that the result was of class integer or that it had a whole-number value.

repeat
	set dialogResult to (display dialog "Enter a starting number:" default answer "")
	try
		set startNumber to (text returned of dialogResult) as number
		-- To accept only entries that coerce directly to class integer.
		if (class of startNumber is integer) then exit repeat
		-- Or, to accept any entries that coerce to whole-number values:
		(* if (startNumber = startNumber as integer) then
			set startNumber to startNumber as integer
			exit repeat
		end if *)
	end try
	display dialog "The starting number needs to be a valid integer!" buttons {"Enter again", "Cancel"} default button 1
end repeat
startNumber

Thank you very much! I hope to repay this community for all of the help one day. So far my skills are rather elementary. Cheers!

I came looking for a safe way to isolate an integer from a string, and found this thread.
And problems…
Martin’s code refuses negative integers (which I don’t need, but nevertheless).
The other samples have problems with dots or comma’s:

"1.1" as number --> 11 - not the same
"1,1" as number --> 1.1 - and neither is this (is it the internal representation?)

"1.1" as integer --> 11 - wrong again
"1,1" as integer --> 1 - yes, it's supposed to work this way

My system uses the comma as decimal separator, and it looks like the dot is simply ignored in the coercion.
Inserting anything else produces an error - only comma and period are problematic.
Something I do not not know about text & numbers? Anything else I’m missing?

For good measure I switched to US English. That just inverted the results.
Booted my sandbox, with an un-tweaked system, and got same result.

My strings have the format integer + one alpha character, i.e. “11m” or “243d”. I need to filter out any typos.
The integer can be any natural number, but in practice it’s 1 to 3 digits.
Eventually I came up with this:

try
	set someString to "1m1m"
	
	set this to (text 1 thru -2 of someString) as integer-- may throw error
	
	-- filter out (lost) dot and comma, and numbers < 1
	if (count (this as text)) ≠ (count (text 1 thru -2 of someString)) or this < 1 then
		error "Number part is not a natural number." number 4000
	end if
	
on error errStr number errNum
	display dialog (errNum as string) & return & errStr
end try

Comments?

Hi, Alastor933.

At the time the original scripts were written, using the wrong decimal separators for the user’s number preferences did error. What you’ve discovered is an unwelcome development. If it’s not a bug, it’s presumably an attempt in AS 2.1 to ignore thousands separators when coercing text to numbers. eg.:

"1,234,567.89" as number --> Commas ignored where used as thousands separators.

An alternative version of your work-round might be:

set someString to "10m"

try
	if (character -1 of someString is not in "abcdefghijklmnopqrstuvwxyz") or (someString contains ".") or (someString contains ",") or (((text 1 thru -2 of someString) as integer) < 0) or ((count someString each word) > 1) then error
on error
	display dialog ("Faulty input: "" & someString & "".
It should be numeric digits followed immediately by a single letter.") with icon stop
end try

Hi, Nigel

Well, it’s out of my hands, then :smiley:

Re your scriplet: I agree filtering out all typos in one go is better - makes for simpler code further on, and all those errors end up in one message.

((count someString each word) > 1)
I swear I stared for at least 30 seconds before I got that! First, I never saw “words of” put like that, and second, I had not considered spaces. Thanks!

(((text 1 thru -2 of someString) as integer) < 0)
I see you count ‘0’ as a natural number. I’m an adherent of the other school :wink: