How to Parse a User Prompt Input "Mike-03-00-25" into Four Variables?

I am new to Twine and I am planning to use the default Harlowe engine.

I have a user prompt to input a string in this format “AAAA-##-##-##” (for example, “Mike-03-00-25”) which will be stored in variable m.
(set:$m to (prompt:“Enter your code:”,“Mike-03-00-25”))

I want to split m into four variables, a, b, c, and d, where a is a string storing “Mike”, and b c d are number variables, 3 0 and 25.

How can I do that?
Thank you.

You can use the (split:) macro to break down the String based input into its four elements…

(set: $m to "Mike-03-00-25")
(set: _elements to (split: '-', $m))

debug: Input "$m" consists of (print: _elements's length) elements: (print: _elements)

…and then use the (num:) macro to convert the 2nd to 4th String elements into Numbers…

(set: $a to _elements's 1st)
(set: $b to (num: _elements's 2nd))
(set: $c to (num: _elements's 3rd))
(set: $d to (num: _elements's 4th))

debug: String: $a; Number 1: $b; Number 2: $c; Number 3: $d

The (num:) macro will throw an error if the String value passed to it contains any characters that are not numerical related!
eg. any characters other than the following will likely cause such an error

1 2 3 4 5 6 7 8 9 0 . -

And there is no simple way to force the end-user into entering a String value with the “AAAA-##-##-##” format you want.


Thanks so much for your reply.
Is there a way to test before the error occurs (total number of components in _elements is not 4 or the user enters a non-numeric value in ##s), and return to the prompt to let the user enter it again?

Thanks again.

I am not too familiar with Harlowe, but you could use the dropdown feature to give users a limited set of choices for the numerical values.

My two previous examples didn’t include any error catching code in them mostly because without an example of your current code I don’t fully know what potential errors may occur.

total number of components in _elements is not 4

At a minimum the 2nd of my examples should check that there are enough “elements” to assign a value to each of your four variables…

(if: _elements's length >= 4)[
	(set: $a to _elements's 1st)
	(set: $b to (num: _elements's 2nd))
	(set: $c to (num: _elements's 3rd))
	(set: $d to (num: _elements's 4th))

…however there are any number of things that may go wrong when processing an end-user entered value, some of them being:
1: Did they enter a value at all?

(if: $m is "")[What to do when no value was supplied?]

2: Did they add additional white SPACE characters to the start and/or end of the value entered?
eg. " Mike-03-00-25 ")

(set: $m to (trimmed: $m))

see: (trimmed:)

2b: Did they add additional white SPACE characters within the entered formatted String value itself?
eg. "Mike -03-00- 25")

(set: $a to (trimmed: _elements's 1st))
(set: $b to (num: (trimmed: _elements's 2nd)))
(set: $c to (num: (trimmed: _elements's 3rd)))
(set: $d to (num: (trimmed: _elements's 4th)))

3: Did they enter the “name” element of the formatted String in a letter-casing different to what you want?.
eg. "mike-03-00-25" or "MIKE-03-00-25" or "mIKe-03-00-25"

(set: $a to (upperfirst: _elements's 1st))

see: (upperfirst: )

4: Did they enter a “name” element longer that what you want?
eg. "Mike the great, who travels this wide land righting wrongs-03-00-25"
(this issues is a lot harder to solve using only the default macros, you will likely need to create one or more Custom Macros)

enters a non-numeric value in ##s

This issue is also hard to solve using just the default macros, because none of them handle the “Is A Numerical Character” or “Contains Non-numerical Character(s)” situations for the String data-type. So again you would likely need to implement one or more Custom Macros.

The following is one potential implementation. The code would need to be placed within your project’s startup tagged Passage.

(set: $isNumerical to (macro: str-type _value, [
	(set: _numerical to true)
	(if: _value's length is 0)[
		(set: _numerical to false)
		(set: _valid to (a: '0','1','2','3','4','5','6','7','8','9','.','-'))
		(for: each _char, ..._value)[
			(if: _numerical)[
				(if: _valid does not contain _char)[
					(set: _numerical to false)
    (output-data: _numerical)

The usage of the above ($isNumerical:) custom macro would likely look something like…

(set: _value to (trimmed: _elements's 2nd))
(if: ($isNumerical: _value))[
	(set: $b to (num: _value))
	(set: $b to 0)

note: It may be possible to use some combination of the String data-type’s operators (like some of) to achieve a similar “is numerical” outcome, but I gave up after trying a couple of combinations.

Thank you so much for the incredibly helpful reply.
One last thing, would you mind showing me how to do the following four lines in SugarCube?

(set: $m to “Mike-03-00-25”)
(set: _elements to (split: ‘-’, $m))
(set: $a to _elements’s 1st)
(set: $b to (num: _elements’s 2nd))

I have already used so much of your time. I will figure out the error prevention in SugarCube myself using your logic above. I am so grateful that you are contributing so much in this forum.

Again, thanks so much.
Incredible answer.

I figured it out myself.
<<set $m to “Mike-03-00-25”>>
<<set _elements to $m.split(‘-’)>>
<<set $m0 to _elements[0]>>
<<set $m1 to Number(_elements[1])>>
<<set $m2 to Number(_elements[2])>>
<<set $m3 to Number(_elements[3])>>
$m0 $m1 $m2 $m3

Please let me know if there is something incorrect.
Thank you.

You’ve correctly used the Number object to convert a numerical String to a Number.

You may want to consider also using the JavaScript <string>.trim() and <string>.toLowerCase() functions, and SugarCube’s own <string>.toUpperFirst() function, to clean up the String value entered by the end-user.

<<set $m to " MiKe -03- 00-25 ">>
<<set _elements to $m.split('-')>>
<<set $m0 to _elements[0].trim().toLowerCase().toUpperFirst()>>
<<set $m1 to Number(_elements[1].trim())>>
<<set $m2 to Number(_elements[2].trim())>>
<<set $m3 to Number(_elements[3].trim())>>

debug: $m0 $m1 $m2 $m3

Thank you so much.