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++?
-
Does this answer your question? [Comparing strings lexicographically](https://stackoverflow.com/questions/14297185/comparing-strings-lexicographically) – Aditya Singh Rathore Apr 13 '21 at 07:41
-
the title of the question is wrong, you want something special not a lexicographical comparison – Alessandro Teruzzi Apr 13 '21 at 07:46
-
1@AlessandroTeruzzi It is lexicographical, just not with the individual characters ordered by the numerical values in the encoding. – molbdnilo Apr 13 '21 at 07:51
-
@AlessandroTeruzzi, could you please suggest a better title? – harsh kapoor Apr 13 '21 at 09:00
-
@harsh kapoor I have updated the answer, but if I were you I would spend an hour or two writing all the unit tests I can think of around it, to make sure it is behaving as intended. – Alessandro Teruzzi Apr 13 '21 at 09:17
4 Answers
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);
}
);
});

- 203,559
- 14
- 181
- 302
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.

- 3,918
- 1
- 27
- 41
-
1Your `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
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

- 5,087
- 3
- 22
- 40
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.

- 3
- 3
-
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