What this lesson covers
A C# string is an immutable sequence of characters. This lesson walks through the everyday operations: creating a string, reading characters, getting the length, joining strings, cutting out a piece with Substring, and the one workaround for editing characters, which is to go through a char[]. The exercise at the end turns "Java" into "TypeScript" using most of these.
Creating, indexing and length
A string literal uses double quotes. Square brackets with a zero-based index return one character as a char, and the Length property (a property, so no parentheses) gives the number of characters:
string str = "Hello";
char first = str[0]; // 'H'
char last = str[str.Length - 1]; // 'o'
The last valid index is always Length - 1. Code ported from Java often calls charAt(i) or length(); in C# those are str[i] and Length.
Joining strings
The + operator joins two strings into a new one, and += joins and stores the result back in the variable:
string name = "John";
string greet = "Welcome";
greet += " to the course, ";
greet += name;
Console.WriteLine(greet); // Welcome to the course, John
Each += creates a new string and copies the old text into it. That's fine for a handful of pieces, but when a loop appends thousands of times, use a StringBuilder, which grows in place.
Substring
Substring cuts a piece out of a string. It has two forms, and they take different arguments:
Substring(start)returns everything from indexstartto the end.Substring(start, length)returnslengthcharacters beginning atstart. The second argument is a length, not an end index. That differs from Java'ssubstring(start, end)and JavaScript'sslice(start, end).
string str = "JavaScript";
Console.WriteLine(str.Substring(4)); // Script
Console.WriteLine(str.Substring(2, 6)); // vaScri (6 characters from index 2)
Console.WriteLine(str.Substring(10)); // prints an empty line
A start index equal to Length gives an empty string, but asking for more characters than remain throws an ArgumentOutOfRangeException. For example, "Bob".Substring(1, 3) throws, because only two characters follow index 1.
Immutability
You can read a character with str[i], but you can't assign to it:
string myStr = "Bob";
myStr[0] = 'J'; // compile error: strings are read-only by index
A variable can still be pointed at a different string, so building a new value works fine:
string myStr = "Bob";
myStr = "Job";
myStr = 'J' + myStr.Substring(1); // "Job" again: a char plus a string gives a string
String methods follow the same rule. str.ToUpper() returns a new string and leaves str unchanged, so the result must be assigned to be kept.
Editing characters through a char array
To change several characters, copy the string into a char[], edit the array, and build a string from it. Array elements are mutable and each assignment takes O(1):
string str = "Andy";
char[] myArr = str.ToCharArray(); // ['A', 'n', 'd', 'y']
myArr[0] = 'a';
myArr[2] = 'D';
str = new string(myArr);
Console.WriteLine(str); // anDy
Note that ToCharArray() makes a copy, so editing the array never touches the original string. The conversion in each direction costs O(n).
Iterating over the characters
A for loop over the indexes visits each character once, which takes O(n) time for a string of length n:
string myStr = "Andy";
for (int i = 0; i < myStr.Length; i++) {
Console.WriteLine(myStr[i]);
}
This prints A, n, d and y on separate lines. A foreach (char c in myStr) loop does the same when you don't need the index.
The exercise, step by step
The goal is to end up with the string "TypeScript", starting from "Java".
- Create
lang. Declarestring lang = "Java";. - Append with
+=. Adding"script"turns it into"Javascript". Because strings can't change, the operator builds a new string and stores it inlang. - Take the tail.
lang.Substring(4)starts at index 4, thes, and returns"script". The single argument means "to the end". - Prefix it.
"Type" + substrgives"Typescript", stored innewLang. - Get a mutable copy.
newLang.ToCharArray()returns achar[]namedcharArray. - Capitalise the letter. The
sis the fifth character, at index 4, socharArray[4] = 'S';. Use single quotes, because the element is achar. - Convert back.
new string(charArray)builds a string from the array, and assigning it tonewLanggives"TypeScript".
string lang = "Java";
lang += "script";
string substr = lang.Substring(4);
string newLang = "Type" + substr;
char[] charArray = newLang.ToCharArray();
charArray[4] = 'S';
newLang = new string(charArray);
Common mistakes
- Treating the second
Substringargument as an end index. It is a length. - Using double quotes for a character.
charArray[4] = "S";doesn't compile, because acharelement needs'S'. - Off-by-one on the last character.
str[str.Length]throws anIndexOutOfRangeException; the last index isLength - 1. - Ignoring the return value. A call such as
lang.Substring(4);on its own computes a string and throws it away. - Writing
.Length()or.length. In C# it isLength, with a capital L and no parentheses.
Key takeaways
- Strings are immutable; every operation that seems to change one produces a new string.
Substring(start)goes to the end, andSubstring(start, length)takes a length.- Go through
ToCharArray()andnew string(...)to edit characters in bulk. - Use
StringBuilderwhen appending many times in a loop.