'How to order strings case-insensitively (not lexicographically)?

I'm attempting to order a list input from a file alphabetically (not lexicographically). So, if the list were:

C d A b

I need it to become: A b C d

Not the lexicographic ordering: A C b d

I'm using string variables to hold the input, so I'm looking for some way to modify the strings I'm comparing to all uppercase or lowercase, or if there's some easier way to force an alphabetic comparison, please impart that wisdom. Thanks!

I should also mention that we are limited to the following libraries for this assignment: iostream, iomanip, fstream, string, as well as C libraries, like cstring, cctype, etc.



Solution 1:[1]

It looks like I'm just going to have to defeat this problem via some very tedious method of character extraction and toppering for each string.

Converting the individual strings to upper case and comparing them is not made particularly worse by being restricted from using algorithm, iterator, etc. The comparison logic is about four lines of code. Even though it would be nice not to have to write those four lines having to write a sorting algorithm is far more difficult and tedious. (Well, assuming that the usual C version of toupper is acceptable in the first place.)

Below I show a simple strcasecmp() implementation and then put it to use in a complete program which uses restricted libraries. The implementation of strcasecmp() itself doesn't use restricted libraries.

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

void toupper(std::string &s) {
  for (char &c : s)
    c = std::toupper(c);
}

bool strcasecmp(std::string lhs, std::string rhs) {
  toupper(lhs); toupper(rhs);
  return lhs < rhs;
}

// restricted libraries used below

#include <algorithm>
#include <iterator>
#include <vector>

// Example usage:
//  > ./a.out <<< "C d A b"
//  A b C d
int main() {
  std::vector<std::string> input;
  std::string word;
  while(std::cin >> word) {
    input.push_back(word);
  }

  std::sort(std::begin(input), std::end(input), strcasecmp);
  std::copy(std::begin(input), std::end(input),
            std::ostream_iterator<std::string>(std::cout, " "));
  std::cout << '\n';
}

Solution 2:[2]

You don't have to modify the strings before sorting. You can sort them in place with a case-insensitive single character comparator and std::sort:

bool case_insensitive_cmp(char lhs, char rhs) {
  return ::toupper(static_cast<unsigned char>(lhs) < 
         ::toupper(static_cast<unsigned char>(rhs);
}

std::string input = ....;
std::sort(input.begin(), input.end(), case_insensitive_cmp);

Solution 3:[3]

std::vector<string> vec {"A", "a", "lorem", "Z"};    
std::sort(vec.begin(),
          vec.end(),
          [](const string& s1, const string& s2) -> bool {
            return strcasecmp(s1.c_str(), s2.c_str()) < 0 ? true : false;
          });

Solution 4:[4]

Use strcasecmp() as comparison function in qsort().

Solution 5:[5]

I am not completely sure how to write it, but what you want to do is convert the strings to lower or uppercase.

If the strings are in an array to begin with, you would run through the list, and save the indexes in order in an (int) array.

Solution 6:[6]

If you're just comparing letters, then a terrible hack which will work is to mask the upper two bits off each character. Then upper and lower case letters fall on top of each other.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 juanchopanza
Solution 3 Udit Gupta
Solution 4 olegarch
Solution 5 Evan Carslake
Solution 6 woolstar