
This primer tutorial covers some of the Makecode basics of strings and characters. These skills will help build your cybersecurity skills and serve you well in competitions with the cyber:bot.
Strings are sequences of characters. For example, “ABC” is a string of characters. Computer software, apps, and Internet communication all depend heavily on strings. For example, much of the communication between browsers and servers over the Internet contains strings. These strings might contain Internet searches, GPS coordinates, text messages and more. Many of the messages you see on web pages and in apps also started as strings.
The Cybersecurity tutorials also rely heavily on strings to exchange radio messages between cyber:bot robots and other micro:bit modules. These strings may have packet data that could contain a code for a particular cyber:bot, navigation instructions, and even sensor values. They can be encrypted by the center and decrypted by the receiver to prevent misuse if intercepted by another team. So, later, you’ll use micro:bit’s to both send and receive, but here, we’ll focus on the string and character basics using projects that a single micro:bit will run.
You will need:
Complete these tutorials first:
You have skills with character and string basics you’ll use in upcoming tutorials for packetizing, parsing, encrypting, decrypting, and evaluating:
After this, you will also be ready to move on to the next tutorials:
A string is a sequence of characters. You are likely to see strings expressed in many different ways in Makecode projects, so this page shows many of the formats you are likely to encounter.
It also introduces how strings can contain data. Because of this, Makecode has many features for manipulating strings. Examples include indexing and built-in blocks.
Strings do not necessarily have to be assigned to variables. For example, here is a string in a serial write block that uses a string as-is:

In many cases, it is better to name a string. If you use a long string more than once, naming it will save considerable code space. For example, instead of two serial write blocks, a string is named once and printed twice:

Inside the micro:bit, characters are actually stored as numbers. In the case of the character A, it’s number is 65. The number for the B character is 66. The numbers are called ASCII codes, and are actually the numbers your keyboard sends your computer when you type the A, B, and other keys. Making projects that manipulate ASCII codes is a first step toward encrypting messages for cybersecurity.
You can find the ASCII Table for codes 0 to 127 in the Reference section:
Strings can contain characters that represent numbers. It is important to understand that a string with “1234” is very different from an int with a value of 1234 that you can add, subtract, multiply, etc. Instead, “1234” are just the characters that represent the numbers.
For example, take a string variable named s that contains the characters “1234”. The quotes make it a string. Without the quotes, n = 1234 creates an int variable that will work in calculations.

Radio and Internet devices often have to convert numbers to strings and add names before sending them to other devices. The devices that receive the string have to find the names and numbers in the string. In many cases, they also have to convert the string representation of the number back to an int or float so that it can be used in calculations. For example, here are two names and numbers:

One project would have to assemble or packetize the string into this before transmitting:

The project running in the receiver might have to parse this data. In this case, parsing would involve breaking the string into its four substrings: “First number”, “1234”, “Second number”, and “5678”. It might also be up to the receiver to find the “1234” and “5678” substrings and convert them back to int variables that the project can use for calculations.
Sending and receiving projects might also have to encrypt the string so that nobody other receivers cannot figure out what the string contains. Here is a very simple example of an encrypted string. The transmitter would have to change each character in some way, and the receiver would have to change each character back to the original before it can process the data. Can you decrypt it and figure out what it really says?

Each character in a string has an index number. That index starts at the first character, counting from zero.
For example, in s = “Hello string”, H has an index of 0, e has an index of 1, l has an index of 2, and so on, up through g with an index of 11. See how even the space between Hello and string is a character with an index?

Makecode has many tools for accessing, manipulating, and converting string information. Here is one indexing example where the 6th character ‘s’ is copied to the c variable and then printed.

Additionally, strings that represent other data types can be converted to those types with built-in blocks. Example:

Let’s start with a project that creates a string, names it s, and prints it.

![]()
The block set (s) to (“ABC 123”) creates a string variable named s. The string it refers to contains the characters A B C 1 2 3. The block serial write line (s) displays the contents of the string named s.
A serial write block allows you to display more than one string at a time. You will find it helpful to add a string that explains what’s about to be printed. So, instead of just serial write line (s), you could use serial write line (join (“s = “)(s)). This will become important when you make larger projects. While adjusting them to work the way you want, you can include information such as the variable name and the location within the project the serial write block is being executed. Here is an example:

Let’s try modifying the project so that it displays s = ABC 123 instead of just ABC 123 in the terminal. That way, you’ll know that the terminal is displaying the contents of the s variable you created. This is very useful in a project that has many variables!

![]()
Each string is a sequence of characters, where each character is defined by a code number. For example, the string “ABC 123” is stored as a sequence of numbers: 65 65 66 67 32 49 50 51 66 49 50 51. These numbers are called ASCII codes. ASCII stands for American Standard Code for Information Exchange.
You can use Makecode blocks to return the ASCII code of a character, and also to return the character for a given ASCII code. Let’s try that!


The block serial write line (“n = ASCII code for A”) displays a heading to help give context to the messages below it.

The block char code from (“ ”) at () returns the ASCII code of a string that contains a single character. The ASCII code for the character A is 65. So, char code from (“A”) at (0) returns 65, and n = char code from (“A”) at (0) stores the value 65 in the variable n.

After that, serial write line (join(“n = “)(n)) displays “n =”, followed by the value of n, which is 65. Lastly, the serial new line just prints an empty line.

After that empty line, serial write line (“c = character with ASCII code 66”) prints another heading.

The text from char code () block accepts an ASCII code, and returns that ASCII code’s character. So, c = text from char code (66) stores the character B in a variable named c.

Since c now stores the character B, serial write line (“c =”, c) prints c = B.

The variable name s is often used in projects to name strings. In projects where many string operations are performed, s might be used repeatedly as a temporary or working variable that ends up being many different strings, each for a brief period of time. Strings in the project that have important meanings should be given descriptive names. One example would be password = “abc123”.
The variable name c can often be found as the name of a string if it stores a single character.
A built-in function is a block that’s always there in Makecode. For strings, Makecode has four important built-in blocks:
The first and second blocks were just used in the last example project, and you will get to experiment with the third and fourth blocks in another activity.
The first 32 ASCII codes are control characters intended for older printers and storage devices. Some of them are still used with terminals today. For example, ASCII character 10, the line feed character, causes the terminal’s cursor to move down a line. In the previous activity, you used the escape sequence \n to add the ASCII 10 to strings.
Printable characters range from 32 (space) to 126 (~). As you have seen from experimentation, the upper-case alphabet uses codes 65 through 90, the lower-case alphabet uses 97-122, and digits are codes 48-57.
Imagine a project that repeatedly calls the text from char code () block inside a for… loop. The first time, it prints text from char code (65), the second time, it prints text from char code (66), and continues all the way through text from char code (90). What do you think you’d see?


You can print your own list of printable ASCII characters with the next example project.


Some projects you will make for cybersecurity encryption and decryption will need to access each character in a string. As a warmup for this, let’s try a project that checks and displays a certain character in a string.


The string s is “ABCDEF 12345”. The string name, followed by a positive index value in square brackets, returns the character at that location in the string. The index starts with A at s[0], B is at s[1], and so on up to the character 5 at s[11]. You can also use -1 through -12 to index characters from rightmost to left.

If your project uses an index that’s larger than the string, it’ll cause an exception. To find out how many characters are in a string, Makecode has that built-in function called length of () that returns the number of characters in a string. Your project can check a string’s length, then can use that result in indexing when accessing characters in that string, so that it never tries to access an out of bounds character. This is especially important when each character is indexed in a loop.
Before indexing all the characters in a string, let’s use length of () to verify that there are 12 characters in the string.


Now that your project can access the length of a string, it can use that number to limit how many characters the project checks in a loop. This makes it possible to access every character safely, without accidentally using an index value that’s too large.
This project displays both the individual characters in the string along with their ASCII codes.


In cybersecurity situations, your project might need to modify a string it receives. One method for modifying strings is to create a larger string by adding smaller strings together. This process is called concatenation.

![]()
The project starts with 4 separate strings: s1, s2, s3, and s4, and adds them together. Addition with string objects is very different from the addition in the int and float objects you are probably familiar with. When string objects are added, they are combined. So, “abc” + “def” results in a string “abcdef”. In our case, set s to (s1 + s2 + s3 + s4) results in a new string variable s that refers to the “Have a nice day.” string.
In the previous activity, a single character was accessed using an index, like set c to (char in (s) at (3)). Your projects can also view segments of strings by using a range instead of a single index number in the square brackets.
Let’s say you have a string named s:
In Makecode-speak, strings are considered immutable. Being immutable means that once created, a string cannot be changed. That doesn’t mean that s = “Have a nice day.” cannot be changed to s = “Have a GREAT day!” It just means that the original “Have a nice day.” string cannot be changed. A block can still grab parts of “Have a nice day.” and use them to create a new string that reads “Have a GREAT day!” The resulting string can even be assigned back to s.

The s variable starts as this string: “Have a nice day.” The second block adds “Have a ” + “GREAT” + ” day” + “!”. See how “Have a “ is s[:7] from the original string? Add the string “GREAT” to that, and then ” day” with a leading space, which is s[11:End], and lastly add “!”, and the string surgery is complete!

This project starts with “Have a nice day.” and then creates a new string sn with the “nice” portion of the original. After that, it demonstrates some more ways to access segments of an original string that were introduced above.


Now that we can concatenate strings with + and access substrings, let’s make a project that starts with “Have a nice day.” and uses parts of it to create “Have a GREAT day!” It’s the equivalent of substituting “GREAT” in place of “nice” and “!” in place of “.”
As you work with this project, keep in mind that the original string “Have a nice day.” was never changed. A new string was created using parts of the original and then assigned equal to s, redefining s.


Sometimes, a project needs to check a string for an exact match. If it’s not an exact match, the program won’t continue! Password protection is an example of this.
Other times, a project might need to ignore strings that don’t contain a certain substring. For example, a radio-broadcasting micro:bit might send names with different ID strings and commands. Each micro:bit can be running a project that looks for its own ID string and only takes action if it detects it in the string.


A string variable named password is declared as “shrubbery”.

Inside a while True loop, the first step is to prompt the user (that’s you) for a password. The result you type is stored in the variable s.

Next, an if…else… block checks if the input you typed, which is stored in s, matches the password variable. The if… block uses the equal to = operator, which returns True if the two strings match, or False if they don’t. When the two strings do match, the break block”breaks out of” the while True loop and moves on to the password-protected part of the project. When it doesn’t match, the project just displays “Password incorrect.” After that, the while True loop repeats.

The project only reaches this point if the user types the correct password.

Sometimes it’s wise to check if a string contains a certain phrase. For example, a micro:bit might be sending radio commands to more than one cyber:bot robot. A unique name could be used to select which cyber:bot in the group should execute the command.
The () find index of () block can help with this. It returns the index of the first character in the matching substring. If it returns 0, it means it found the character at the very beginning of the string. If it returns 5, it means it started at the fifth character in the string. If it doesn’t find a match, it returns -1.
Here is an example of how () find index of () can be used:
Keep in mind that you can also search for characters. Just use a single character in the search, like (s) find index of (“A”).
As mentioned in the Strings and Characters page, string objects also have useful blocks. Heads up, the upper block is in the cyberbots support section. Here are a few examples to try:

Here we have three examples of searching for substrings with () find index of (). After finding the index of the first and second instances of one substring, it looks for a substring that isn’t there. Examine the searches and results carefully.

Does this make sense? The first instance of “Arthur” starts at character 0 in s. Since Lancelot isn’t in there, it returns -1.

Sometimes a project has to make the distinction between an exact match and the presence or absence of a term in a string. Even if () find index of () returns 0, that doesn’t prove that there aren’t more characters following the match. One way to solve this is to use the is equal to = operator to check if the string is an exact match. If it isn’t, then use the () find index of () block to check if the substring is anywhere in the string.



This example program introduces two more useful string blocks: set () to upper and split () at (), While we use the convert dictionary to string block its just because Makecode isn’t able to serial write anything thats isn’t a string so we need to convert the array.


The first routine declares a string, names it string, and then prints it for reference.

The set (string) to upper block returns an upper case version of the original string, and prints it:

The split (string) at (“ “) block splits a string with separators into substrings. By default, the separator is empty, but you could pass it a comma, a space, or anything else, for example. Many data strings are comma delimited, and need to be split before each individual data item can be examined.

One use for the set () to upper block is to make menu systems accept whatever the user types, regardless of what combination of uppercase and lowercase characters have been used. This can be helpful in menu systems, because we might just want the project to do what it’s told, regardless of whether we typed run, RUN, Run, RUn, or some other combination. By calling set () to upper first, it makes it so the program only has to check for one word: RUN
This next example is a modified version of comp_find_check_your_turn from Compare, Find, Check. By adding a single set () to upper block, we can avoid checking for every conceivable combination of run, Run, RUN, RuN, etc.



When the micro:bit receives strings from other devices, it may need to convert them to other data types to process their data. For example, one micro:bit might use a string to transmit a list of int values. The transmitter has to convert its int values to string representations before sending. The receiver will have to convert the string representations of integers back to int values before it can use them in calculations.
Before converting from int to string and back to int again, let’s look at just how differently they behave with an operator that can be used with either type.


Makecode recognizes the intended data type when you initialize a variable, based on format.
set (s) to (“1234”) creates a variable named s of type string, note the enclosing double-quotes.
set (n) to (1234) creates a variable named n of type int; note the lack of double-quotes. (There’s no decimal point, so it’s not a float.)
The plus + operator performs integer addition on int variables, and so set (n2) to (n + n) mathematically adds the two 1234 integers for a result of 2468.
In contrast, that + operator will concatenate two strings—in other words it will join them together. That is why set (s2) to (s + s) resulted in “12341234”.
You may have already seen how to get a string and convert it to int in the Computer–micro:bit Talk tutorial. Here, the int result after calculations is also converted back to a string.

