
Editorial illustration.
Originally published 23 June 2023; rewritten and reviewed on 15 October 2026.
“Level” looks like an easy palindrome. A phrase containing spaces, punctuation and accented letters makes the problem more interesting. Before writing the loop, I would decide which characters count and what equality means for this particular application.
Begin with a precise, small contract
This example compares characters case-insensitively but keeps spaces and punctuation significant. A null input is rejected; an empty string matches under this definition.
static bool IsPalindrome(string value)
{
ArgumentNullException.ThrowIfNull(value);
int left = 0;
int right = value.Length - 1;
while (left < right)
{
if (char.ToUpperInvariant(value[left]) !=
char.ToUpperInvariant(value[right]))
return false;
left++;
right--;
}
return true;
}
The helper uses UTF-16 char values and invariant character casing. It is an instructional implementation, not a complete treatment of every writing system or user-perceived character.
Change normalisation only when required
If a product wants to ignore punctuation and spaces, make that rule explicit and test the normalisation separately. If grapheme clusters, supplementary Unicode characters or culture-sensitive comparison matter, use an appropriate text representation instead of assuming every character occupies one char.
The original reverse-and-compare approach is also useful for learning, but it creates additional data. A two-pointer approach makes the stopping condition visible and uses constant additional storage for this restricted contract.
Test the definition, not just the happy path
Include odd and even lengths, mixed case, an empty string, a mismatch near the centre and punctuation. Add language-specific cases only after deciding the intended rules.
The lesson goes beyond palindromes: a short algorithm becomes dependable when its input contract is clear enough that two developers would agree on the expected answer.