NoSenseEtAl
NoSenseEtAl

Reputation: 30118

C++ std:: string starts_with/ends_with case insensitive versions?

C++20 added starts_with, ends_with to std::string.

Is there a nice way to get it to be case insensitive?

Note that perf matters so I do not want to lowercase/uppercase both strings(or std::min(len1, len2) parts of them).

Unlike regular <algorithm> algorithms starts_with has no overload with comparator so I see no nice way to do this.

And I kind of understand that 90+% of cases are case sensitive, and that member fns in C++ are avoided unless extremely useful... so I know why this limitation exists, I am just curious if something relatively readable can be hacked together in C++20 without me manually calling std::equal(or ranges version of equal) with custom comparator.

Upvotes: 1

Views: 3172

Answers (3)

e102_gamma
e102_gamma

Reputation: 41

I also faced this problem recently.

If you don't mind using boost, there is istarts_with and iends_with functions.

They do exactly what you need.

Upvotes: 2

Marshall Clow
Marshall Clow

Reputation: 16690

std::mismatch(s1.begin(), s1.end(), s2.begin(), s2.end(), <comparator>) will do what you want. You have to write the case-insensitve comparator, but I'm sure you can figure that out.

Upvotes: 1

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 123084

I was curious to see how the suggestion to apply this answer works out. This is the result.

Code from said answer:

struct ci_char_traits : public char_traits<char> {
    static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
    static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
    static bool lt(char c1, char c2) { return toupper(c1) <  toupper(c2); }
    static int compare(const char* s1, const char* s2, size_t n) {
        while( n-- != 0 ) {
            if( toupper(*s1) < toupper(*s2) ) return -1;
            if( toupper(*s1) > toupper(*s2) ) return 1;
            ++s1; ++s2;
        }
        return 0;
    }
    static const char* find(const char* s, int n, char a) {
        while( n-- > 0 && toupper(*s) != toupper(a) ) {
            ++s;
        }
        return s;
    }
};

typedef std::basic_string<char, ci_char_traits> ci_string;

There the answer suggested to use ci_string instead of std::string. Here we just want to create ci_views to std::strings:

typedef std::basic_string_view<char, ci_char_traits> ci_string_view;

int main()
{   
    std::string x{"ABCD"};
    std::string y{"abcd"};
    std::cout << ci_string_view{x.begin(),x.end()}.ends_with(ci_string_view{y.begin(),y.end()});
}

Output:

1

Live Example

Upvotes: 2

Related Questions