Updated on

To get one char out of a string in C#, we index into it with myString[0], or call char.Parse() when the string holds exactly one character. To get all of them, ToCharArray() copies the string into a new char[].

The article also extends into reading characters through ReadOnlySpan<char> and converting arrays of strings to arrays of characters.

To download the source code for this article, you can visit our GitHub repository.

Let’s start.

How Do We Get a Single Char From a String?

A string in C# is a sequence of char values, so getting one character out of it is either a lookup or a parse.

To read the character at a known position, we use the indexer. myString[0] returns the first char and myString[^1] returns the last one. Both throw an IndexOutOfRangeException when the string is empty.

When the whole string should be a single character, such as a Y or N answer, we call char.Parse(). According to Microsoft Learn, it throws a FormatException when “the length of s is not 1″, and an ArgumentNullException when the string is null.

When the input comes from a user or a file, char.TryParse() runs the same check without throwing. It returns false instead, and the output value is undefined in that case.

Convert.ToChar() with a string argument behaves the same way as char.Parse(), so we don’t need it here.

We keep our helper methods in a static StringHelper class, in a file that starts with using System.Text;, and call them from Program.cs. If we have a single character string, we can convert the string to a char:

public static char ConvertSingleCharacterStringToChar(string inputString)
{
    return char.Parse(inputString);
}

Here, our method makes use of the char.Parse() method. It takes a string as input and returns its only character if the string has exactly one character. Note that char.Parse() will throw an exception if the input string’s length is not exactly 1.

Getting a Char by Its Position

When the string is longer than one character, char.Parse() can’t help us, and the indexer is the usual answer:

public static char GetCharacterAtIndex(string inputString, int index)
{
    return inputString[index];
}

The method returns the char at the position we ask for, counting from zero. In our own code we would usually index the string directly, and the ^1 index from ranges and indices gives us the last character:

string myString = "Hello World!";
char firstChar = StringHelper.GetCharacterAtIndex(myString, 0);
char lastChar = myString[^1];

Here, firstChar is 'H' and lastChar is '!'. Both lines throw an IndexOutOfRangeException if myString is empty, so we check myString.Length first when that can happen. We explain that exception in more detail in our article on IndexOutOfRangeException.

Using char.TryParse() When the Input Might Be Wrong

char.Parse() throws when the input is wrong. For input from a user or a file, char.TryParse() is the safer choice. It follows the same pattern as int.TryParse() and the other TryParse methods:

public static bool TryConvertSingleCharacterStringToChar(string? inputString, out char result)
{
    return char.TryParse(inputString, out result);
}

It returns true and the character when the string has exactly one character. In every other case, null included, it returns false without throwing, and result holds no value we should use:

if (StringHelper.TryConvertSingleCharacterStringToChar("AB", out char parsed))
    Console.WriteLine(parsed);
else
    Console.WriteLine("Not a single character");

Since "AB" has two characters, we get:

Not a single character

What Happens With Emoji?

A char holds one UTF-16 code unit, and some characters need two of them. Most emoji are in that group:

string thumbsUp = "\U0001F44D";

Console.WriteLine(thumbsUp.Length);
Console.WriteLine(char.IsHighSurrogate(thumbsUp[0]));
Console.WriteLine(char.TryParse(thumbsUp, out _));

The string holds a single thumbs-up sign, and the output is:

2
True
False

Its Length is 2. The first char is only the high half of a surrogate pair. char.TryParse() refuses the string because it is two code units long, so none of the methods above can return the emoji as one char. The same pair causes trouble when we truncate a string by length, because the cut can fall between its two halves.

When we need the whole symbol, the Rune type from System.Text reads both halves as one value. With using System.Text; at the top of Program.cs, we only add the second line if our thumbsUp from above is already there:

string thumbsUp = "\U0001F44D";
Rune symbol = Rune.GetRuneAt(thumbsUp, 0);

symbol.Value is 0x1F44D, the Unicode code point of the thumbs-up sign.

Converting a String to a Char Array

Let’s look at an example to show how to accomplish the conversion of a string with more than one character to a char array using a straightforward method:

public static char[] ConvertStringToCharArray(string inputString)
{
    return inputString.ToCharArray();
}

The ConvertStringToCharArray() method takes a string input and then makes use of the ToCharArray() method to convert the input string into a character array. The ToCharArray() method returns a new array containing the characters of the string.

Let’s test it out, skipping the first line if our myString from earlier is already in Program.cs:

string myString = "Hello World!";
char[] charArray = StringHelper.ConvertStringToCharArray(myString);

We call the method passing a string to it, and it returns a character array containing the individual characters of the string. The result, charArray, can then be used for further processing or manipulation as needed.

This method is a convenient way to convert a string to a character array, and it leverages the built-in functionality provided by the string class in C#.

If we only need part of the string, the ToCharArray(6, 5) overload copies five characters starting at index 6, which gives us World. For the opposite direction, we have a separate article on how to convert a char array back to a string.

Using ReadOnlySpan as an Alternative to a Char Array

ReadOnlySpan<T> is a type in C# that provides a read-only view over a block of memory, without creating a new array or copying data. It’s particularly useful when dealing with performance-critical scenarios or when we want to work with data without the overhead of array creation.

To learn more about the ReadOnlySpan type, check out our article on using Span to improve application performance. Other ways to get a span from a string are in our article on how to convert a string to a span.

In the context of character data, ReadOnlySpan<char> can be considered an alternative to char[] when we need to work with a sequence of characters without modifying the underlying data.

Let’s see how we can achieve this:

public static ReadOnlySpan<char> ConvertStringToCharArrayUsingReadOnlySpan(string inputString)
{
    return inputString.AsSpan();
}

The ConvertStringToCharArrayUsingReadOnlySpan() method converts a string to a read-only span of characters. It utilizes the AsSpan() method to create a read-only view of the characters in the input string. The resulting ReadOnlySpan<char> allows for efficient and read-only access to the underlying character data of the string without allocating a new array.

Now, we call the method:

ReadOnlySpan<char> charArrayReadOnlySpan = StringHelper.ConvertStringToCharArrayUsingReadOnlySpan(myString);

Comparison of ToCharArray and AsSpan

  • ToCharArray() creates a new char[] on the heap, while AsSpan() simply creates a ReadOnlySpan<char> view over the existing data
  • The resulting char[] is mutable meaning we can modify the contents of the array, while ReadOnlySpan<char> is read-only so we cannot
  • ToCharArray() allocates a new array and copies every character into it, while AsSpan() allocates nothing. For our "Hello World!" string, ToCharArray() allocated 48 bytes and AsSpan() allocated 0 bytes on .NET 10

Converting String Array to Char Array Using Loop

Now, let’s take it a step further and explore the conversion of an array of strings to an array of characters.

Let’s see how to accomplish this with the help of StringBuilder:

public static char[] ConvertStringArrayToCharArrayUsingLoop(string[] stringArray)
{
    var combinedString = new StringBuilder();

    foreach (var str in stringArray)
    {
        combinedString.Append(str);
    }

    var result = new char[combinedString.Length];
    combinedString.CopyTo(0, result, 0, result.Length);

    return result;
}

Here, we first create a StringBuilder and concatenate the strings together using the Append() method. Next, we allocate a result char array based on the length of the concatenated string. Finally, we copy the contents of the combinedString into our result array and return it. Note that we don’t add a separator when concatenating the elements of the stringArray.

Converting String Array to Char Array Using LINQ

We can also achieve the same result using LINQ instead of a loop:

public static char[] ConvertStringArrayToCharArrayUsingLinq(string[] stringArray)
{
    return stringArray.SelectMany(s => s.ToCharArray()).ToArray();
}

This ConvertStringArrayToCharArrayUsingLinq() method converts an array of strings, stringArray, into a single char[] using LINQ (Language Integrated Query).

For more details on LINQ, please check out our article on LINQ.

Here we use LINQ’s SelectMany() to transform each string in the array into a sequence of characters. The ToCharArray() method is applied to each string, resulting in a sequence of characters. Finally, ToArray() converts the sequence into a single char[].

This method performs the concatenation of characters from all strings in the collection into a single char[]. It’s a concise and readable way to achieve the desired result using LINQ’s expressive syntax.

Conclusion

We’ve seen how to get a single char from a string with the indexer, char.Parse() and char.TryParse(), and how to convert a string to a char array with ToCharArray() or read it through a ReadOnlySpan<char>. We also went a step further, converting an array of strings into a char array with a loop and with LINQ.

If a string can hold emoji, remember that one symbol may take two char values, and Rune is the type that holds the whole symbol.

Tested with .NET 10.0.10 and xUnit 2.9.3.