Victor Brunell
Victor Brunell

Reputation: 6418

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.

Upvotes: 2

Views: 3216

Answers (6)

Udit Gupta
Udit Gupta

Reputation: 11

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;
          });

Upvotes: 1

bames53
bames53

Reputation: 88155

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';
}

Upvotes: 1

woolstar
woolstar

Reputation: 5083

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.

Upvotes: 0

juanchopanza
juanchopanza

Reputation: 227400

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);

Upvotes: 1

Evan Carslake
Evan Carslake

Reputation: 2349

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.

Upvotes: 0

olegarch
olegarch

Reputation: 3891

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

Upvotes: 0

Related Questions