Regular expressions

Bob
Bob in C#
using System.Text.RegularExpressions;

public static class Bob
{
    public static string Response(string message)
    {
        if (IsSilence(message))
            return "Fine. Be that way!";

        if (IsYell(message) && IsQuestion(message))
            return "Calm down, I know what I'm doing!";

        if (IsYell(message))
            return "Whoa, chill out!";

        if (IsQuestion(message))
            return "Sure.";

        return "Whatever.";
    }

    private static bool IsSilence(string message)
    {
        return Regex.IsMatch(message, @"^\s*$");
    }

    private static bool IsYell(string message)
    {
        return Regex.IsMatch(message, @"^[^\p{Ll}]*\p{Lu}[^\p{Ll}]*$");
    }

    private static bool IsQuestion(string message)
    {
        return Regex.IsMatch(message, @"\?\s*$");
    }
}

In this approach you have a series of if statements using private methods that use regular expressions to evaluate the conditions. As soon as the right condition is found, the correct response is returned.

Note

Note that there are no else if or else statements. If an if statement returns, then an else if or else is not needed. Execution will either return or will continue to the next statement anyway.

Silence

The IsSilence() method should match when the string is either empty or only contains whitespace characters. We can use the following regular expression for that: ^\s*$. This pattern matches when there are zero or more whitespace characters (\s*) between the begin (^) and end (^) of the input.

To match on this regular expression, we use Regex.IsMatch(), which takes an input string and a regular expression pattern and returns a bool indicating if the input matches the pattern:

Regex.IsMatch(message, @"^\s*$");
Note

When defining regular expression patterns, consider defining them with a verbatim string literal (prefixed with @) to prevent having to escape any backslash characters.

Yell

The IsYell() method should match when the string contains only uppercase letters and optionally zero or more non-letter characters. We could use the following regular expression for that: ^[^a-z]*[A-Z]+[^a-z]*$. This says that the input must start (^) with zero or more non-lowercase letters (^a-z]*), followed by one or more uppercase letters (A-Z]+) and end ($) with zero or more non-lowercase letters (^a-z]*). while this passes the tests, it only works with ASCII strings; any Unicode uppercase letters would not match the above pattern (e.g. Ä  would not match as an uppercase letter).

Unicode

Luckily, .NET regular expressions support Unicode character groups, which include character groups for uppercase letters (\p{Lu}) and lowercase letters (\p{Ll}). With this, we can rewrite our regular expression to: ^[^\p{Ll}]*\p{Lu}+[^\p{Ll}]*$. And now, our regular expression will correct match lower- and uppercase Unicode letters:

Regex.IsMatch(message, @"^[^\p{Ll}]*\p{Lu}+[^\p{Ll}]*$"");

Question

The IsQuestion() method should match when the string ends with a question mark (?), optionally followed by zero or more whitespace characters. We can use the following regular expression for that: \?\s*$. What this regular expressions says is that the input must end ($) with a question mark (\?, which we need to escape as to match the ? character class) and zero or more whitespace (\s*) characters.

Regex.IsMatch(message, @"\?\s*$");

Extension methods

For this exercise you could add behavior to the String type using Extension methods, like so

private static bool IsSilence(this string message)
{
    return Regex.IsMatch(message, @"^\s*$");
}

which would be called like so

if (message.IsSilence())
    return "Fine. Be that way!";

Shortening

When the body of a function is a single expression, the function can be implemented as a member-bodied expression, like so

private bool IsSilence(string message) =>
    Regex.IsMatch(message, @"^\s*$");

or

private bool IsSilence(string message) => Regex.IsMatch(message, @"^\s*$");
11th Dec 2024 · Found it useful?