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:
| Escape | What it puts in the string |
|---|---|
\n | A line break. It is two characters: carriage return and line feed (CR LF). |
\r | A carriage return (CR). |
\t | A 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 throwsERR_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.2comes out as0.3. A decimal on its own inprintlncomes out with just the digits needed to be the same number:0.30000000000000004. - Booleans have no
toString(): use anifwith 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()andlen()count bytes, andfind()returns a position in bytes.text[i],foreachandsplit("")go byte by byte: an é comes out split into two pieces that can't be printed on their own.upper()andlower()only change the letters from A to Z. Accented letters and the ñ stay as they are.isAlpha()andisAlnum()givefalseif there is an accented letter or an ñ.==,contains(),count(),replace()andsplit()with a separator work fine with any text.
Methods
| Method | What it does | Returns |
|---|---|---|
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) throwsERR_INVALID_OPERATION, and a method that doesn't exist,ERR_ATTRIBUTE_NOT_FOUND. - They are exceptions: you catch them with
tryandcatch(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.
substringhas to be a string, andn, an integer. Otherwise it throwsERR_TYPE_MISMATCH.nstarts at 1: with 0 or a negative number it throwsERR_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 atchr(10)and remove from each line the carriage return it may have at the end withstrip().
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, intotrueorfalse;nil, intonone; and a list or a map, intoObject. - 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 with0xand 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_MISMATCHwith the messageCan 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
infornan, it also throwsERR_TYPE_MISMATCH, with the messageCan 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 throwsERR_TYPE_MISMATCHwhen 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, andupper(),lower()andisAlpha()don't know about accents: see Accented letters. -
"\n"is two characters (CR LF): see Writing strings andsplit. -
The
toBool()of"false"istrue: seetoBool. -
toFloat()doesn't throw exceptions: seetoFloat. -
VM bugs worth avoiding, each with its own warning:
findfrom the third occurrence on,rightStripwith a string of spaces,replacewith an empty string, which hangs, and a number assigned totext[i], which closes the VM.
All the known issues of JARU, together, are in Known issues.