String Functions - ThePix/QuestJS GitHub Wiki

A string in JavaScript can be terminated with single quotes, double quotes or backquotes, but you must use the same at the start and end. Using backquotes allows interpolation, but that is outside the scope of this discussion.

The Text Processor offers a lot of options when handling strings.

Quest 6 String Functions

sentenceCase(str)

Returns the string with the first letter capitalised.

titleCase(str)

Returns the string with the first letter or each word capitalised.

sentenceCaseForHTML(str)

sentenceCase and titleCase are very simple; they just take the string as-is, and change the case of letters on that basis. Usually that is fine, but if you have formatting commands in the text, they may well fail.

let s = "{i:simple} text to show capitalisation."

sentenceCase(s)
-> '{i:simple} text to show capitalisation.'

Note that sentenceCase has failed to capitalise "simple" as the first character of the word is "{".

To allow for that, there is sentenceCaseForHTML and titleCaseForHTML. The sentenceCaseForHTML function is fairly straight forward; it just digs down into the HTML to find the actual first word. It will be a bit slower, but no real downside.

Note that it works on HTML, not text processor directives. Either use processText first, or use the "cap" text processor directive.

let s = "{i:simple} text to show capitalisation."

// This will not work properly
sentenceCaseForHTML(s)
-> '{i:simple} text to show capitalisation.'

// Process the text first
sentenceCaseForHTML(processText(s))
-> '<i>Simple</i> text to show capitalisation.'

// Or use the "cap" text processor
s = "{cap:{i:simple} text to show capitalisation.}"
processText(s)
-> '<i>Simple</i> text to show capitalisation.'

titleCaseForHTML(str)

The titleCaseForHTML function works quite differently to sentenceCaseForHTML. It does not change the string, but instead inserts it into a set of HTML tags that will make the browser capitalise each word.

let s = "simple text to {i:show} capitalisation."

titleCaseForHTML(s)
-> '<span style="text-transform: capitalize;">simple text to {i:show} capitalisation.</span>'

When printed on screen, the user will see:

Simple Text To Show Capitalisation.

If you later break the string up, you could lose the span tag, and it may not work properly. If you insert text into the middle of it, that text will get capitalised, whether you want that or not. If you compare the string to another, you need to remember that it is not actually capitalised. Unlike sentenceCaseForHTML, this works fine with text processor directives.

As a general rule, if this is a string you are formatting to display immediately, use titleCaseForHTML, but if this is a string that is not formatted, or you are storing to use later, use titleCase.

Note that the "title" text processor directive uses titleCaseForHTML, as the text processor is generally used for formatting and for printing directly to screen.

prefix(item, options)

If options.multiple is true, returns the item name to be prefixed to the command response, otherwise returns an empty string. This is useful for commands that allow multiple ojects, as you can just put this at the start of the string. The default command script will pass options to the item, with multiple set as appropriate, which can pass this to prefix.

msg(prefix(item, options) + "Okay.")

I think a better way is to use the "multi" text processor directive.

formatList(itemArray, options)

Creates a string from an array. If the array element is a string, that is used, if it is an item, lang.getName is used (and passed the options) to derive a name - generally the item's alias. Items are sorted alphabetically, based on the "name" attribute.

Options:

  • article: DEFINITE (for "the") or INDEFINITE (for "a"), defaults to none (see lang.getName)
  • sep: separator (defaults to comma)
  • lastSep: separator for last two items (just separator if not provided); you should not include any spaces
  • modified: item aliases modified (see lang.getName) (defaults to false)
  • nothing: return this if the list is empty (defaults to empty string)
  • count: if this is a number, the name will be prefixed by that (instead of the article)
  • doNotSort if true the list is not sorted (otherwise sorted alphabetically)
  • separateEnsembles: if true, ensembles are listed as the separate items
  • other attributes as described for lang.getName

For example:

formatList(listOfOjects, {def:"a", lastSep:"and"})
-> "a hat, Mary and some boots"

formatList(list, {lastSep:"or", nothing:"nowhere");
-> north, east or up

If you set settings.oxfordComma to true, extra commas will be (erroneously, in my view!) added before the last joiner when there are three or more items.

toRoman(number)

Converts the given number to Roman numerals. Can only handle numbers from 1 to 3999 (which is a limitation inherent in Roman numerals).

getDateTime()

Gets the current game date/time as a nicely formatted string. Set up the format in settings.js.

displayMoney(n)

Gets the given number as a string formatted as currency. Set up the format in settings.js.

getDir(s)

Converts the string to the standard direction name, so "down", "dn" and "d" will all return "down". Uses the lang.exit_list array, so language neutral.

Language specific string functions

lang.conjugate(item, verb)

Returns the correct form of the given verb (string) for the given item.

lang.pronounVerb(item, verb, options)

Returns a string containing the pronoun for the item with the verb conjugated, capitalised if "options.capitalise" is true.

lang.pronounVerb(w.book, "say", {capitalise:true})
//--> 'It says'
lang.pronounVerb(w.boots, "say", {capitalise:true})
//--> 'They say'

lang.nounVerb(item, verb, options)

Returns a string containing the alias for the item with the verb conjugated, capitalised if "options.capitalise" is true.

lang.nounVerb(w.book, "say", {capitalise:true})
//--> 'The book says'

lang.toWords(number)

Converts the given number (rounded to a whole number) to the actual words (one, two, etc.). You are going to get an error if it has more than forty digits, but JavaScript does not readily handle integers over about 9 quadrillion anyway.

lang.toWords(-2084)
//--> 'minus two thousand and eighty-four'
lang.toWords(1405425762084)
//--> 'one trillion, four hundred and five billion, four hundred and twenty-five million, seven hundred and sixty-two thousand, and eighty-four'

You can also add a string, which should be a noun. Quest will return the number followed by the noun, appropriately pluralised.

lang.toWords(2, 'log')
//--> 'two logs'
lang.toWords(1, 'stadium')
//--> 'one stadium'
lang.toWords(3, 'stadium')
//--> 'three stadia'

lang.toOrdinal(number)

Converts the given number to the ordinal word (first, second, etc.). Will happily handle negative numbers and huge numbers, whether that is meaningful or not.

lang.toOrdinal(2084)
//--> 'two thousand and eighty-fourth'

JavaScript string functions

These belong to the string itself, so take the form s.func. This is just a few of the many available.

length

Actually not a function, so no brackets.

const s = 'This is a string'
const length = s.length

replace(oldValue, newValue)

Returns a new string, in which oldValue has been replaced by newValue.

If oldValue is a string, it will only replace the first instance in the string. If you want to replace every instance, use a regular expression tagged as global.

const s = 'This is a string'
const s2 = s.replace('s', '$')
// s2 will be 'Thi$ is a string'
const s3 = s.replace(/s/g, '$')
// s2 will be 'Thi$ is a $tring'

You can also use capture groups in your regular expression, and then refer to them with $1, $2, etc. This example will convert codes in the text into text processor directives for commands that look up the terms.

s = 'You look at the [[cottage|house]] and see a strange [[chimney|chimney]] at the side.'
s.replace(/\[\[(.+?)\|(.+?)\]\]/g, '{cmd:ask computer about $2:$1}')
//-> 'You look at the {cmd:ask computer about house:cottage} and see a strange {cmd:ask computer about chimney:chimney} at the side.'

split(sep) and join(sep)

The split function will break your string into bits, putting each bit into an array, which is returned. It will be split wherever there is a sep, so if sep is a space, it will be split wherever there is a space (and the spaces discarded). The separator can also be a regular expression.

The join function does the reverse, going from an array to a single string, inserting sep between each element.

const s = 'This is a string'
const a = s.split(' ')
// a is now ['This', 'is', 'a', 'string']
const s2 = a.join(' ')
// s2 is now the same as s

match(regex)

Tests the string against the regular expression (if regex is a string it will get converted to a regular expression). If the "g" flag is not used, only the first complete match and its related capturing groups are returned. If the "g" flag is used for the regex (indicating "global"), all results matching the complete regular expression will be returned, but capturing groups will not (if you need both "g" and capture groups, use matchAll).

Returns null if no match.

toUpperCase(), toLowerCase()

Returns a new string with every character converted to upper or lower case.

endsWith(s), startsWith(s)

Returns true if the string starts with or ends with the string s.

substring, substr, slice

These three methods all return a section of the given string. The "substr" method is deprecated, so is only here to note that it exists and should not be used.

The substring and slice methods take two numbers as parameters, the start address and the end address. Addresses count from zero, so in the first example below, the fifth character is the start of the returned value. The second parameter indicates the first character not returned, so the length of the returned string will be the difference between the parameters. If the second parameter is omitted, the end of the string is assumed

const s = 'This is my string'
s.substring(4, 10)
// -> ' is my'
s.slice(4, 10)
// -> ' is my'
s.substring(10)
// -> ' string'
s.slice(10)
// -> ' string'

The substring does not care which way round the parameters are, so s.substring(10, 4) would give the result above. Slice will return an empty string. Slice can handle negative numbers; it indicates the position is counted from the right.

s.slice(-4)
// -> 'ring'
s.slice(-4, -2)
// -> 'ri'
⚠️ **GitHub.com Fallback** ⚠️