A Deeper Look at the std::string Class

Case-Insensitive String Comparison

How can I implement a case-insensitive string comparison using std::string?

Abstract art representing computer programming

Implementing a case-insensitive string comparison in C++ requires a bit more work than in some other languages, but it's certainly doable. Here's an efficient way to create a case-insensitive comparison function for std::string:

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

bool iequals(
  const std::string& a, const std::string& b
) {
  return std::equal(
    a.begin(), a.end(), b.begin(), b.end(),
    [](char a, char b) {
      return std::tolower(
        static_cast<unsigned char>(a)) ==
        std::tolower(static_cast<unsigned char>(b));
      }
  );
}

int main() {
  std::string str1{"Hello, World!"};
  std::string str2{"hElLo, wOrLd!"};
  std::string str3{"Hello, Universe!"};

  std::cout << std::boolalpha;
  std::cout << "str1 == str2 (case-sensitive): "
            << (str1 == str2) << '\n';
  std::cout << "str1 == str2 (case-insensitive): "
            << iequals(str1, str2) << '\n';  
  std::cout << "str1 == str3 (case-insensitive): "
            << iequals(str1, str3) << '\n';  
}
str1 == str2 (case-sensitive): false
str1 == str2 (case-insensitive): true
str1 == str3 (case-insensitive): false

Let's break down the iequals() function:

  1. We use std::equal() to compare the strings character by character.
  2. The lambda function [](char a, char b) { ... } compares each pair of characters.
  3. std::tolower() from <cctype> converts each character to lowercase before comparison.
  4. We use static_cast<unsigned char> to avoid undefined behavior with negative char values.

This method is efficient because it stops at the first mismatch and doesn't create any temporary strings.

For more complex scenarios, like locale-aware comparisons, you might want to use the <locale> library:

#include <locale>

bool iequals_locale(
  const std::string& a, const std::string& b,
  const std::locale& loc = std::locale()
) {
  return std::equal(
    a.begin(), a.end(), b.begin(), b.end(),
    [&loc](char a, char b) {
      return std::tolower(a, loc) ==
        std::tolower(b, loc);
      }
  );
}

This version respects the locale settings, which can be important for certain languages.

Remember, these methods work well for ASCII strings, but may not handle Unicode correctly. For proper Unicode support, consider using a dedicated Unicode library like ICU.

If you need to do many comparisons against a single string, you might want to create lowercase versions of the strings first and then compare those:

std::string to_lower(std::string s) {
  std::transform(
    s.begin(), s.end(), s.begin(),
    [](unsigned char c) {
      return std::tolower(c);
    }
  );
  return s;
}

// Usage:
std::string lower1 = to_lower(str1);
std::string lower2 = to_lower(str2);
bool equal = (lower1 == lower2);

This can be more efficient if you're doing multiple comparisons, as you only lowercase each string once.

Answers to questions are automatically generated and may not have been reviewed.

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 125 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved