Strings
editCompare strings
// Ordinal comparisons, with or without case
Assert.True("Content-Type".EqualsIgnoreCase("content-type"));
Assert.False("Content-Type".EqualsOrdinal("content-type"));
Assert.True("Content-Type: text/html".ContainsIgnoreCase("TEXT/HTML"));
// EqualsIgnoreCase and EqualsOrdinal accept null values
string? missing = null;
Assert.False(missing.EqualsIgnoreCase("value"));
Assert.True(missing.EqualsOrdinal(null));EqualsIgnoreCase and ContainsIgnoreCase use StringComparison.OrdinalIgnoreCase, and EqualsOrdinal uses StringComparison.Ordinal. The comparison is the same whatever the current culture, which is what identifiers, file extensions, HTTP headers or configuration keys need.
Remove a prefix or a suffix
Assert.Equal("Home", "HomeController".RemoveSuffix("Controller", StringComparison.Ordinal));
Assert.Equal("Repository", "IRepository".RemovePrefix("I", StringComparison.Ordinal));
// Nothing is removed when the string does not start or end with the value
Assert.Equal("Repository", "Repository".RemoveSuffix("Controller", StringComparison.Ordinal));
// Choose the comparison, for instance to ignore case
Assert.Equal("Home", "HomeCONTROLLER".RemoveSuffix("Controller", StringComparison.OrdinalIgnoreCase));RemovePrefix and RemoveSuffix remove one occurrence, only when the string starts or ends with it. The overloads without a StringComparison use an ordinal comparison. With a culture-sensitive comparison, the part removed is the part that matched, which can be longer or shorter than the value you pass.
Turn empty strings into null
// Turn empty (and optionally whitespace-only) strings into null
Assert.Null("".Nullify(trim: false));
Assert.Null(" ".Nullify(trim: true));
Assert.Equal(" ", " ".Nullify(trim: false));
// With trim: true, the returned value is trimmed
Assert.Equal("value", " value ".Nullify(trim: true));Nullify returns null for null and empty strings. With trim: true, it trims the string first, so a string that contains only white space also gives null, and any other string is returned trimmed.
Remove diacritics
Assert.Equal("Creme brulee a l'Ile-de-France", "Crème brûlée à l'Île-de-France".RemoveDiacritics());RemoveDiacritics removes the accents and other combining marks, for instance to build a URL slug or to search without accents. It also works when the application runs in invariant globalization mode. A string that contains only ASCII characters is returned as is, without allocating.
Replace several characters
var invalidCharacters = SearchValues.Create(@"/\:*?");
Assert.Equal("reports_2024_q1_draft_", @"reports/2024\q1:draft?".ReplaceAny(invalidCharacters, '_'));ReplaceAny replaces every character of a SearchValues<char> with the same character, and returns the original string when there is nothing to replace. Create the SearchValues<char> once, in a static readonly field, when you call it often.
Split lines
var lines = new List<string>();
var separators = new List<string>();
foreach (var (line, separator) in "first\r\nsecond\nthird".SplitLines())
{
lines.Add(line.ToString());
separators.Add(separator.ToString());
}
Assert.Equal(["first", "second", "third"], lines);
Assert.Equal(["\r\n", "\n", ""], separators);SplitLines enumerates the lines of a string or a ReadOnlySpan<char> without allocating: each line is a ReadOnlySpan<char>, with the line break that ended it (empty for the last line). Call ToString on a line only when you need to keep it. A text that ends with a line break does not produce an empty last line.
\r\n is one line break. Choose the other characters that end a line with LineBreakMode:
var unicodeLines = new List<string>();
foreach (var line in "a\u2028b".SplitLines())
{
unicodeLines.Add(line.Line.ToString());
}
var standardLines = new List<string>();
foreach (var line in "a\u2028b".SplitLines(LineBreakMode.Standard))
{
standardLines.Add(line.Line.ToString());
}
// By default, Unicode line separators such as U+2028 also break lines
Assert.Equal(["a", "b"], unicodeLines);
// LineBreakMode.Standard only breaks lines on \r and \n
Assert.Equal(["a\u2028b"], standardLines);| LineBreakMode | Line breaks |
|---|---|
| Standard | \r, \n |
| Unicode (default) | \r, \n, \u0085 (next line), (line separator), (paragraph separator) |
| UnicodeWithLegacyControls | The Unicode ones, plus \v (vertical tab) and \f (form feed) |
StringBuilder helpers
var sb = new StringBuilder();
foreach (var item in new[] { "apple", "banana", "cherry" })
{
sb.Append(item).Append(',');
}
// Check and remove the trailing separator without converting the builder to a string
Assert.True(sb.EndsWith(','));
sb.TrimEnd(',');
Assert.Equal("apple,banana,cherry", sb.ToString());
Assert.True(sb.StartsWith("apple"));StartsWith and EndsWith check the content of a StringBuilder without creating a string, and TrimStart, TrimEnd and Trim remove a repeated character at its ends. A builder that contains only this character becomes empty. To append values formatted with the invariant culture, see Formatting and cultures.
Escape Markdown
MarkdownBuilder is obsolete. Use MarkdownEscaper from the Meziantou.Framework.Markdown package instead: it escapes text, code, links and table cells, and its output is checked against the Markdown parser. See Write Markdown text.