Is there a built in function for std::string in C++ to compare two strings alphabetically when either string can be uppercase or lowercase?

后端 未结 5 509
盖世英雄少女心
盖世英雄少女心 2021-01-18 06:08

I know for C++ that basic comparative operators can accomplish the task if both words are either entirely lower or entirely upper case. I have an array of strings and letter

相关标签:
5条回答
  • 2021-01-18 06:47

    In C++ usually less-than (bool less(type, type)) is used in places of tri-value function compare (int cmp(type, type)). Of course each one of them can be trivially defined in terms of the other.

    Here's something that can easily be plugged into STL algorithms:

    template<class String>
    struct ciless {
      locale l_;
    
      explicit ciless(locale l = locale()) : l_(l) {}
    
      bool operator() (
          String const &a
        , String const &b) const
      {
        auto fa = a.begin();
        auto fb = b.begin();
    
        while (fa != a.end()
          && fb != b.end()
          && (tolower(*fa, l_) == tolower(*fb, l_)))
        {
          ++fa;
          ++fb;
        }
    
        return
          (fa == a.end() && fb != b.end())
          || (
              fa != a.end()
            && fb != b.end()
            && tolower(*fa, l_) < tolower(*fb, l_));
      }
    };
    

    And here's something that can convert less() into java-style compare():

    template<class T, class Less = std::less<T>>
    struct compare
    {
      Less l_;
    
      explicit compare(Less l = Less()) : l_(l) {}
    
      int operator() (
          T const &a
        , T const &b) const
      {
        if (l_(a, b))
          return -1;
    
        if (l_(b, a))
          return 1;
    
        return 0;
      }
    };
    
    0 讨论(0)
  • 2021-01-18 06:52

    I don't know of any case-insensitive functions in the standard library, but you can specify a custom predicate for std::equal:

    std::string a("hello");
    std::string b("HELLO");
    std::cout << std::equal(a.begin(), a.end(), b.begin(),
        [] (const char& a, const char& b)
        {
            return (std::tolower(a) == std::tolower(b));
        });
    

    For a solution which takes locale into account, refer to Case insensitive std::string.find().

    #include <locale>
    
    template<typename charT = std::string::value_type>
    struct my_equal {
        my_equal( const std::locale& loc ) : loc_(loc) {}
        bool operator()(charT ch1, charT ch2) {
            return std::toupper(ch1, loc_) == std::toupper(ch2, loc_);
        }
    private:
        const std::locale& loc_;
    };
    
    int main()
    {
        std::string a("hello");
        std::string b("HELLO");
        std::cout << std::equal(a.begin(), a.end(), b.begin(),
            my_equal<>(std::locale()));
    }
    
    0 讨论(0)
  • 2021-01-18 06:57

    Nothing standard, but if you happen to be developing for Windows or have access to a Posix interface you could use the following: https://msdn.microsoft.com/en-us/library/k59z8dwe.aspx

    // didn't run it through a compiler
    // but it would look like something like this:
    {
       using namespace std;
       string a = "HELLO"s;
       string b = "HelLO"s;
       bool bIsMatch = _stricmp(a.c_str(), b.c_str()) == 0;  // bIsMatch = true
    }
    
    0 讨论(0)
  • 2021-01-18 07:04

    You can use Boost String Algorithms:

    #include <string>
    #include <cassert>
    
    #include <boost/algorithm/string.hpp>
    
    int main() {
        std::string s { "Test" };
        assert(boost::iequals(s, "TEST"));
    }
    
    0 讨论(0)
  • 2021-01-18 07:11

    Yes there is a case insensitive way to compare strings in C++. The key is that std::string is a template:

    template <class charT,
              class traits = char_traits<charT>,
              class Allocator = allocator<charT>>
    class basic_string;
    

    The traits here control how the charT's relate to each other. For normal std::string, they do what you'd expect, but we can just write our own traits that are case insensitive:

    struct case_insensitive_traits
    : char_traits<char>
    {
        static bool eq(char a, char b) { return tolower(a) == tolower(b); }
        static bool ne(char a, char b) { return !eq(a, b); }
        static bool lt(char a, char b) { return tolower(a) < tolower(b); }
        static bool gt(char a, char b) { return tolower(a) > tolower(b); }
    
        static int compare(const char* a, const char* b, size_t n)
        {
            for (size_t i = 0; i < n; ++i) {
                int delta = tolower(a[i]) - tolower(b[i]);
                if (delta != 0) return delta;
            }
            return 0;
        }
    
        static const char* find(const char* s, size_t n, char c)
        {
            c = tolower(c);
            for (size_t i = 0; i < n; ++i, ++s) {
                if (tolower(*s) == c) return s;
            }
            return nullptr;
        }
    };
    

    With that:

    using case_insensitive_string = std::basic_string<char, case_insensitive_traits>;
    
    case_insensitive_string a{"hello"};
    case_insensitive_string b{"hElLo"};
    
    assert(a == b);
    
    0 讨论(0)
提交回复
热议问题