Another untested solution.
If I missed a case, I'm sure someone will point it out, but here goes:
#include <iostream>
#include <algorithm>
#include <string>
#include <cctype>
#include <vector>
#include <iterator>
using namespace std;
int main() {
std::vector <std::string> StringVect = { "BB", "aA", "12", "b", "AA", "&", "[", "**", "1" };
std::sort(StringVect.begin(), StringVect.end(), []
(const std::string& s1, const std::string& s2)
{
if (s1.empty() || s2.empty())
return s1 < s2;
// a convenience array
bool ac[] = { isalpha(s1[0]), isalpha(s2[0]),
isdigit(s1[0]), isdigit(s2[0]),
!isalnum(s1[0]), !isalnum(s2[0]) };
// If both strings start with the same type, then return
// s1 < s2
if ((ac[0] && ac[1]) || // if both alpha strings
(ac[2] && ac[3]) || // if both digit strings
(ac[4] && ac[5])) // if both non-alphanumeric strings
return s1 < s2;
// if first string is alpha, or second string is not alphanumeric
// the strings are in order, else they are not
return (ac[0] || ac[5]);
});
copy(StringVect.begin(), StringVect.end(), ostream_iterator<string>(cout, "\n"));
}
Basically, the condition says this:
1) If one of the strings are empty, then return s1 < s2
2) If both strings start with the same character type, just return s1 < s2
3) If the first string starts with an alpha, or if the second string is not an alphanumeric, then the strings are in order and return true
, else return false. The trick here is to realize that step 2) eliminated all combinations of both strings being of the same type, so our check at the step 3) stage becomes simplified.
Live example: http://ideone.com/jxxhIY
Edit:
If you are checking for case-insensitive strings, then you need to change the code, and add the case-insensitive check. I won't add the code, since there are multiple ways, both with their respective advantages and disadvantages, of doing a case-insensitive compare.
#include <iostream>
#include <algorithm>
#include <string>
#include <cctype>
#include <vector>
#include <iterator>
using namespace std;
int main() {
std::vector <std::string> StringVect = { "BB", "aA", "12", "b", "AA", "&", "[", "**", "1" };
std::sort(StringVect.begin(), StringVect.end(), []
(const std::string& s1, const std::string& s2)
{
if (s1.empty() || s2.empty())
return s1 < s2;
// a convenience array
bool ac[] = { isalpha(s1[0]), isalpha(s2[0]),
isdigit(s1[0]), isdigit(s2[0]),
!isalnum(s1[0]), !isalnum(s2[0]) };
// If both strings start with the same type, then return
// s1 < s2
if ((ac[2] && ac[3]) || (ac[4] && ac[5]))
return s1 < s2;
// case insensitive
if (ac[0] && ac[1]) // both strings are alpha
return myCaseInsensitiveComp(s1, s2); //returns true if s1 < s2, false otherwise
// if first string is alpha, or second string is not alphanumeric
// the strings are in order, else they are not
return (ac[0] || ac[5]);
});
copy(StringVect.begin(), StringVect.end(), ostream_iterator<string>(cout, "\n"));
}
Again, the myCaseInsensitiveComp
is a stub that you should fill in with a function that accomplishes this goal. For a link, see this:
Case insensitive string comparison in C++