0

I want to create a function to compare two strings in dictionary order so that I can sort the strings "aa", "AA", "Bb","bb" in the order "aa" < "AA" < "bb" < "Bb". How can I achieve this in C++?

4 Answers4

2

You might do

auto compare_string = [](const auto& lhss, const auto& rhss){
    return std::lexicographical_compare(
        lhss.begin(), lhss.end(),
        rhss.begin(), rhss.end(),
        [](const auto& lhsc, const auto& rhsc){
            auto proj = [](char c){ return std::tuple(std::tolower(c), std::isupper(c)); };
            return proj(lhsc) < proj(rhsc);
        }
    );
});

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
2

Your desired way of sorting the string is not the one implemented by default by std::string. However, you can pass in your std::char_traits template parameter and customized the sorting.

https://en.cppreference.com/w/cpp/string/char_traits

Here a pretty old but still interesting discussion of the implementation of a case insensitive string: http://www.gotw.ca/gotw/029.htm

#include <string>
#include <string_view>
#include <iostream>
#include <cctype>
#include <cassert>


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


 int main()
 {  
     typedef std::basic_string<char,special_char_traits> ss;
     //handle the case highligheted by Jarod42
     assert(!special_char_traits::lt('a','a'));
     assert(!special_char_traits::lt('A','A'));
     assert(special_char_traits::lt('a','A'));
     assert(!special_char_traits::lt('A','a'));
     assert(!special_char_traits::lt('b','A'));
     assert(special_char_traits::lt('A','b'));

     std::cout << (std::string("AA") < std::string("aa")) << " " << (ss("AA") < ss("aa")) << std::endl;    
 }

STILL UNTESTED FOR SEVERAL CASES

The compare function is delegating the comparison of the single characters to the lt function provided above.

Alessandro Teruzzi
  • 3,918
  • 1
  • 27
  • 41
  • 1
    Your `lt` method seems strange... `lt('a', 'a')` is false. Your also rely on ASCII (`'A' < 'a'`) (EBCDIC has reverse ordering). – Jarod42 Apr 13 '21 at 09:01
0
std::string a = "A";
std::string b = "B";
if(a < b)
    // Do what you want.

std::string has the < operator overloaded and that is everything you need to sort them.

See also: Using the less than comparison operator for strings

gonutz
  • 5,087
  • 3
  • 22
  • 40
0

just create a function which takes takes two strings as input. on the function creates STL set. Insert two strings.They are now sorted in dictionary order inside set.

  • I think SO questioners are looking for implementable solutions. Giving the words doesn't typically help. Where's the programming code to go with this answer? – Kat Apr 15 '21 at 06:09