Skip to main content

Strings

A string is a piece of text: a name, a message, a line you read from a file or that arrives over the network. You write it between quotes and keep it in a variable like any other value. What applies to all data types is in Data types.

Strings don't need use: their methods are always there, and you call them with a dot on a variable, as in name.upper(). A string never changes: each method returns a new string and leaves the original as it was.

var name = "Ann"
var shout = name.upper()
println(shout) // ANN
println(name) // Ann

Strings work the same on Windows and on every board.

Writing strings​

A string goes between double or single quotes. Inside one kind you can use the other. "" is the empty string.

var greeting = "Hello"
var quote = 'Say "hello"'
var english = "It's"
var empty = ""
println(quote) // Say "hello"
println(english) // It's

Inside the quotes, the backslash \ starts an escape:

EscapeWhat it puts in the string
\nA line break. It is two characters: carriage return and line feed (CR LF).
\rA carriage return (CR).
\tA tab.
\\A backslash.

No other combination is an escape: the backslash stays in the string, followed by the character after it. "\"" is not a quote: it is a two-character string, the backslash and the quote. To write double quotes, open the string with single quotes, and the other way round.

A string can carry on in the next line of the program. Each line break of the program becomes a space:

var notice = "Press A to jump
and B to shoot"
println(notice) // Press A to jump and B to shoot

Reading the characters​

text[i] returns the character at position i, as a one-character string. The first position is 0, and the last one, text.size() - 1:

var word = "cats"
println(word[0]) // c
println(word[word.size() - 1]) // s
  • A negative position, or one past the last, throws ERR_INDEX_OUT_OF_RANGE. There are no positions counted from the end.
  • The position has to be an integer. With a decimal, even 1.0, it throws ERR_TYPE_MISMATCH.

To walk through a string, use foreach, which gives you one character in each turn, or a for over the positions:

var word = "cats"
foreach (var letter in word)
print(letter, " ")
end
println("")
for (var i = word.size() - 1; i >= 0; i--)
print(word[i])
end
println("")
c a t s
stac

Changing a character​

text[i] = "x" changes the character at position i. As strings never change, a new string is actually made and stored in the variable. Another variable that held the same text stays as it was:

var a = "cats"
var b = a
a[0] = "r"
println(a) // rats
println(b) // cats

Only the first character of what you assign counts: a[1] = "XY" puts an X. What you assign has to be a string with at least one character: with anything else, like a number, it throws ERR_TYPE_MISMATCH, and with an empty string, ERR_INVALID_VALUE. In both cases the string stays as it was.

Taking a piece​

There is no method that takes a piece of a string. You do it with a loop:

func piece(text, from, upTo)
var result = ""
for (var i = from; i < upTo; i++)
result = result + text[i]
end
return result
end

var sentence = "Hello world"
println(piece(sentence, 6, 11)) // world

If the text has a separator, such as a comma, it is easier to break it up with split.

Joining strings​

+ joins two strings:

var name = "Ann"
var greeting = "Hello, " + name + "!"
println(greeting) // Hello, Ann!

+ only joins a string with another string. A string plus a number, a boolean, nil or a list throws ERR_TYPE_MISMATCH, with the message Unsupported operand types for operator '+'.:

var lives = 3
try
var text = "Lives: " + lives
catch (var e)
println(e.message) // Unsupported operand types for operator '+'.
end

To join a number, turn it into a string first with its toString() method (number methods are in Data types). If you only want to print it, you don't need to: print and println take several arguments and write them one after the other (see Standard library).

var lives = 3
var seconds = 12.5
var line = "Lives: " + lives.toString() + " Time: " + seconds.toString()
println(line) // Lives: 3 Time: 12.5
println("Lives: ", lives) // Lives: 3
  • The toString() of a decimal gives 15 digits at most: 0.1 + 0.2 comes out as 0.3. A decimal on its own in println comes out with just the digits needed to be the same number: 0.30000000000000004.
  • Booleans have no toString(): use an if with the two strings.
  • To join all the items of a list, use join.

Comparing strings​

== and != compare the text, character by character, and tell upper case from lower case. To compare without minding case, turn both into lower case first:

var a = "Hello"
var b = "hello"
println(a == b) // false
var la = a.lower()
var lb = b.lower()
println(la == lb) // true

<, >, <= and >= don't compare text: between two different strings they always give false, and <= and >= give true only when the strings are equal. To sort strings, put them in a list and use sort().

Accented letters​

Strings keep their text in UTF-8: an accented letter, an ñ or a symbol such as € takes two bytes or more, and the methods count bytes, not letters.

var word = "café"
println(word.size()) // 5
var upperCase = word.upper()
println(upperCase) // CAFé
  • size() and len() count bytes, and find() returns a position in bytes.
  • text[i], foreach and split("") go byte by byte: an é comes out split into two pieces that can't be printed on their own.
  • upper() and lower() only change the letters from A to Z. Accented letters and the ñ stay as they are.
  • isAlpha() and isAlnum() give false if there is an accented letter or an ñ.
  • ==, contains(), count(), replace() and split() with a separator work fine with any text.

Methods​

MethodWhat it doesReturns
size()Counts the bytes.Integer
find(substring, n)Looks for a substring.Integer: the position, or -1
contains(substring)Checks whether it contains it.true or false
count(substring)Counts how many times it appears.Integer
startsWith(prefix)Checks whether it starts that way.true or false
endsWith(suffix)Checks whether it ends that way.true or false
lower()Turns it into lower case.New string
upper()Turns it into upper case.New string
strip()Removes the spaces on both sides.New string
leftStrip()Removes the spaces at the start.New string
rightStrip()Removes the spaces at the end.New string
replace(old, new)Swaps one text for another.New string
split(separator)Breaks the string up at a separator.List of strings
join(list)Joins the items of a list, with the string between them.New string
isAlpha()Checks whether everything is letters.true or false
isDigit()Checks whether everything is digits.true or false
isAlnum()Checks whether everything is letters or digits.true or false
toInt()Converts to an integer.Integer
toFloat()Converts to a decimal.Decimal, or an error value
toBool()Converts to a boolean.true or false

Errors common to all of them:

  • With more or fewer arguments than their own they throw ERR_INVALID_ARG_NUMBER, and with an argument of another type, ERR_TYPE_MISMATCH.
  • The name without brackets (text.size) throws ERR_INVALID_OPERATION, and a method that doesn't exist, ERR_ATTRIBUTE_NOT_FOUND.
  • They are exceptions: you catch them with try and catch (see Errors and exceptions).

text.size()​

Returns the number of bytes in the string: the number of letters if it has no accents. It is the same as len(text).

var name = "Ann"
var empty = ""
println(name.size()) // 3
println(empty.size()) // 0

text.find(substring, n)​

Looks for substring and returns the position where it starts, counting from 0, or -1 if it isn't there. n is optional: the number of the occurrence you are looking for. Without it, it looks for the first one.

var sentence = "Hello world"
println(sentence.find("world")) // 6
println(sentence.find("o")) // 4
println(sentence.find("o", 2)) // 7
println(sentence.find("x")) // -1
  • It tells upper case from lower case.
  • With an empty substring it returns 0.
  • substring has to be a string, and n, an integer. Otherwise it throws ERR_TYPE_MISMATCH.
  • n starts at 1: with 0 or a negative number it throws ERR_INVALID_VALUE.

text.contains(substring)​

Returns true if substring is in the text. It tells upper case from lower case, and with an empty substring it gives true.

var sentence = "Hello world"
println(sentence.contains("world")) // true
println(sentence.contains("World")) // false

text.count(substring)​

Counts how many times substring appears, without counting overlapping letters twice: in "banana", "ana" appears once. With an empty substring it returns 0.

var fruit = "banana"
println(fruit.count("a")) // 3
println(fruit.count("ana")) // 1

text.startsWith(prefix)​

Returns true if the text starts with prefix. It tells upper case from lower case, and with "" it gives true.

var file = "level3.map"
println(file.startsWith("level")) // true
println(file.startsWith("Level")) // false

text.endsWith(suffix)​

Returns true if the text ends with suffix. It tells upper case from lower case, and with "" it gives true.

var file = "level3.map"
println(file.endsWith(".map")) // true
println(file.endsWith(".MAP")) // false

text.lower()​

Returns the text in lower case. It only changes the letters from A to Z: accented letters and the Ñ stay as they are.

var title = "CAFÉ CRÈME"
println(title.lower()) // cafÉ crÈme

text.upper()​

Returns the text in upper case. It only changes the letters from a to z.

var name = "Zoë"
println(name.upper()) // ZOë

text.strip()​

Removes the spaces, tabs and line breaks at the start and at the end. The ones in the middle stay.

var input = "  hello   world \n"
var clean = input.strip()
println("[", clean, "]") // [hello world]

text.leftStrip()​

Like strip(), but only at the start.

var input = "   hello   "
println("[", input.leftStrip(), "]") // [hello ]

text.rightStrip()​

Like strip(), but only at the end.

var input = "   hello   "
println("[", input.rightStrip(), "]") // [ hello]

text.replace(old, new)​

Returns the text with every occurrence of old swapped for new. If old isn't there, or is an empty string, it returns the same text. To remove a text, put "" in new.

var sentence = "Hello world"
println(sentence.replace("world", "JARU")) // Hello JARU
println(sentence.replace("o", "0")) // Hell0 w0rld
var hour = "12:30:05"
println(hour.replace(":", "")) // 123005

Both arguments have to be strings. Otherwise it throws ERR_TYPE_MISMATCH.

text.split(separator)​

Breaks the text up at every occurrence of separator and returns a list with the pieces, without the separator.

var csv = "red,green,blue"
var colours = csv.split(",")
println(colours) // [red, green, blue]
println(colours.size()) // 3
  • Two separators in a row, or one at the start or at the end, give empty pieces: "a,,b," gives four pieces, "a", "", "b" and "".
  • If the separator isn't there, the list has a single piece: the whole text. An empty string gives a list with one empty string.
  • With "" as the separator, it breaks the text up byte by byte (see Accented letters).
  • To break up into lines a text you wrote in the program, use "\n". A text that comes from outside (from a file or the network) may have its line breaks without the carriage return, and then "\n" doesn't split it: split it at chr(10) and remove from each line the carriage return it may have at the end with strip().

separator.join(list)​

Joins the items of list into a string, with the text you call it on between one item and the next. As a method can't be called on a string written between quotes, keep the separator in a variable first:

var colours = ["red", "green", "blue"]
var comma = ", "
println(comma.join(colours)) // red, green, blue
var nothing = ""
println(nothing.join(colours)) // redgreenblue
  • Items that aren't strings are converted: numbers, as with toString(); booleans, into true or false; nil, into none; and a list or a map, into Object.
  • With an empty list it returns "".
  • The argument has to be a list (an array won't do). Otherwise it throws ERR_TYPE_MISMATCH.

text.isAlpha()​

Returns true if all the characters are letters from a to z, upper or lower case. An empty string, a space, an accented letter or an ñ give false.

var a = "Jaru"
var b = "café"
println(a.isAlpha()) // true
println(b.isAlpha()) // false

text.isDigit()​

Returns true if all the characters are digits from 0 to 9. A sign, a decimal point or an empty string give false. It tells you whether a text is an integer without a sign before you convert it with toInt().

var a = "2026"
var b = "-12"
var c = "1.5"
println(a.isDigit()) // true
println(b.isDigit()) // false
println(c.isDigit()) // false

text.isAlnum()​

Returns true if all the characters are letters from a to z or digits. A _, a space, an accented letter or an empty string give false.

var a = "level3"
var b = "level_3"
println(a.isAlnum()) // true
println(b.isAlnum()) // false

text.toInt()​

Converts the text into an integer.

var a = "42"
var b = "3.7"
var c = "0x1F"
println(a.toInt() + 1) // 43
println(b.toInt()) // 3
println(c.toInt()) // 31
  • It accepts spaces at the start, a sign, decimals (it keeps the whole part, without rounding: "-3.7" gives -3), hexadecimal with 0x and an exponent ("1e3" gives 1000).
  • If the text isn't a number, is empty or has anything after the number, even a space, it throws ERR_TYPE_MISMATCH with the message Can not convert '…' to a number.
  • If the number, without its fractional part, doesn't fit in an integer (over 2,147,483,647 or under -2,147,483,648), or is inf or nan, it also throws ERR_TYPE_MISMATCH, with the message Can not convert '…' to an integer: out of range (-2147483648 to 2147483647).
var text = "12abc"
try
var n = text.toInt()
println(n)
catch (var e)
println(e.message) // Can not convert '12abc' to a number.
end

text.toFloat()​

Converts the text into a decimal, with all its digits: "3.14" gives the same as 3.14. It accepts the same as toInt().

var a = "2.5"
var b = "42"
println(a.toFloat() * 2) // 5
println(b.toFloat()) // 42

If the text isn't a number, it doesn't throw any exception: it returns an error value, which prints as Error 7 (the number of ERR_TYPE_MISMATCH). try doesn't catch it. Error values are explained in Errors and exceptions. To tell whether it failed, check whether type() of the result gives tError.

If the text may not be a number, convert it with JSON.parse(text), from the JSON module. It reads all the digits, although a decimal may come out different in the last one, and, if the text can't be read, it throws ERR_INVALID_VALUE, which try does catch:

use JSON

var text = "3.14"
try
var x = JSON.parse(text)
var double = x * 2
println(double.toString()) // 6.28
catch (var e)
println("Not a number: ", text)
end

text.toBool()​

Returns false if the string is empty, and true with any other text, "false" and "0" included.

var a = ""
var b = "false"
println(a.toBool()) // false
println(b.toBool()) // true

To read a "true" or a "false" written in a text, compare it:

var text = "true"
var active = (text == "true")
println(active) // true

Complete example​

This program reads some scores written as text, the way they would arrive from a file or over the network. It cleans them up, drops the ones that aren't a number and prints them sorted by name.

var data = "ann:120, LUIS:95 ,  marta:200,paul:abc"
var table = {}

foreach (var entry in data.split(","))
var parts = entry.split(":")
var name = parts[0].strip()
var points = parts[1].strip()
if (points.isDigit()) then
table[name.lower()] = points.toInt()
else
println("Not points: ", name, " -> ", points)
end
end

var names = table.keys()
names.sort()
foreach (var n in names)
var line = n.upper() + ": " + table[n].toString()
println(line)
end
var comma = ", "
println("Players: ", comma.join(names))
Not points: paul -> abc
ANN: 120
LUIS: 95
MARTA: 200
Players: ann, luis, marta

Pitfalls and known issues​

  • A method can't be called on a string written between quotes, and it can't be indexed either. "hello".upper() doesn't compile (Expected identifier in method name.), and "hello"[0] compiles, but throws ERR_TYPE_MISMATCH when it runs. Keep the string in a variable first. More in Basic syntax.

    var shout = "hello".upper()
  • A string plus a number is an error when the program runs: see Joining strings.

  • < and > don't sort text: see Comparing strings.

  • size() counts bytes, and upper(), lower() and isAlpha() don't know about accents: see Accented letters.

  • "\n" is two characters (CR LF): see Writing strings and split.

  • The toBool() of "false" is true: see toBool.

  • toFloat() doesn't throw exceptions: see toFloat.

  • VM bugs worth avoiding, each with its own warning: find from the third occurrence on, rightStrip with a string of spaces, replace with an empty string, which hangs, and a number assigned to text[i], which closes the VM.

All the known issues of JARU, together, are in Known issues.