C ++排序 - 正常字母后的特殊字符

时间:2015-04-02 02:14:45

标签: c++ sorting c++11

我有一个字符串向量,它包含像

这样的字符串
BB
aA
12
b
AA
&
[
**
1

使用带有C ++的默认排序()我得到了这个排序列表

&
**
1
12
AA
BB
[
aA
b

而不是那样,我需要先订购普通字母A, a, B, b....,然后按照正常的ASCII顺序排列0-9, *, [, , ~, !....之类的“特殊”字符。

我真的不知道如何改变矢量的排序方式,以确保它按顺序排列。感谢。

4 个答案:

答案 0 :(得分:2)

您可以指定自己的函数来比较要使用的排序值。

bool myfunction(std::string a, std::string b){ ... }

std::sort(data.begin(), data.end(), myfunction);

使用myfunction您可以指定所需的顺序。以下是有关排序的更多信息:

http://www.cplusplus.com/reference/algorithm/sort/

答案 1 :(得分:2)

另一种未经测试的解决方案。

如果我错过了一个案例,我相信有人会指出它,但是这里有:

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

基本上,条件说明了这一点:

1)如果其中一个字符串为空,则返回s1&lt; S2

2)如果两个字符串都以相同的字符类型开头,则只返回s1&lt; S2

3)如果第一个字符串以alpha开头,或者第二个字符串不是字母数字,则字符串按顺序返回true,否则返回false。这里的技巧是要意识到步骤2)消除了两个相同类型的字符串的所有组合,因此我们在步骤3)阶段的检查变得简单。

实例:http://ideone.com/jxxhIY

编辑:

如果要检查不区分大小写的字符串,则需要更改代码,并添加不区分大小写的检查。我不会添加代码,因为有多种方法,无论是各自的优点和缺点,还是进行不区分大小写的比较。

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

同样,myCaseInsensitiveComp是一个存根,你应该填写一个实现这个目标的函数。有关链接,请参阅:

Case insensitive string comparison in C++

答案 2 :(得分:1)

无论如何,您需要为它实现自己的比较逻辑,并将其与sort一起使用。

(1)您可以将比较函数对象赋予sort,并在其中实现您自己的比较(小于)逻辑,例如:

struct my_comparison {
    bool operator()(const string &a, const string &b) {
        // implement the less than logic here
    }
}

然后:

sort(v.begin(), v.end(), my_comparison());

参考:http://en.cppreference.com/w/cpp/algorithm/sort

(2)您可以实现自己的char_traits<char>来创建一个使用特殊比较逻辑的特殊string。如:

struct my_char_traits : public char_traits<char> 
              // just inherit all the other functions
              // that we don't need to replace
{
    static bool eq(char c1, char c2) { 
        // implement the comparison logic here
    }
    static bool lt(char c1, char c2)
        // implement the comparison logic here
    }
    static int compare(const char* s1, const char* s2, size_t n)
        // implement the comparison logic here
    }
};

然后:

typedef basic_string<char, my_char_traits> my_string;
vector<my_string> v;
// ...
sort(v.begin(), v.end());

参考:http://en.cppreference.com/w/cpp/string/char_traits

答案 3 :(得分:1)

免责声明:未经测试的代码。

这是一个应该起作用的比较函数的实现。解决方案的关键是将与要在比较函数中更改其顺序的字符对应的值重新编码为数组。

void initializeEncoding(char encoding[])
{
   for (int i = 0; i < 256; ++i )
   {
      encoding[i] = i;
   }

   // Now re-encode for letters, numbers, and other special characters.
   // The control characters end at 31. 32 == ' ', the space character.

   int nextIndex = 32;

   // Re-encode the uppercase letters.
   for ( int c = 'A'; c <= 'Z'; ++c, ++nextIndex )
   {
      encoding[c] = nextIndex;
   }

   // Re-encode the lowercase letters.
   for ( int c = 'a'; c <= 'z'; ++c, ++nextIndex )
   {
      encoding[c] = nextIndex;
   }

   // Re-encode the numbers.
   for ( int c = '0'; c <= '9'; ++c, ++nextIndex )
   {
      encoding[c] = nextIndex;
   }

   // Re-encode the special chracters.
   char const* specialChars = " !\"#$%&'()*+,-./:;<=>?[\\]^_`{|}~";
   for ( char* cp = specialChars; *cp != '\0'; ++cp, ++nextIndex )
   {
      encoding[*cp] = nextIndex;
   }
}

bool mycompare(char const* s1, char const* s2)
{
   static char encoding[256];
   static bool initialized = false;
   if ( !initialized )
   {
      initializeEncoding(encoding);
      initialized = true;
   }

   for ( ; *s1 != '\0' && *s2 != '\0'; ++s1, ++s2 )
   {
      if ( encoding[*s1] != encoding[*s2] )
      {
         break;
      }
   }

   return ((encoding[*s1] - encoding[*s2]) < 0);
}

bool mycompare(std::string const& s1, std::string const& s2)
{
   return mycompare(s1.c_str(), s2.c_str());
}