Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 排序std::字符串中包含数字?_C++_String_Sorting - Fatal编程技术网

C++ 排序std::字符串中包含数字?

C++ 排序std::字符串中包含数字?,c++,string,sorting,C++,String,Sorting,我目前正在按std::string

我目前正在按std::string<运算符进行排序。问题在于:

30<9。30出现在9之前,因为3<9,Windows9x有这个问题。我怎样才能对它们进行数字排序,使“9条狗”之后出现“30只狐狸”。我还应该补充一点,我使用的是UTF8编码


谢谢

您可以创建一个自定义比较函数,用于
std::sort
。此函数必须检查字符串是否以数值开头。如果是,则使用stringstream之类的机制将每个字符串的数字部分转换为
int
。然后比较这两个整数值。如果值的比较相等,则按字典顺序比较字符串的非数字部分。否则,如果字符串不包含数字部分,只需按正常情况按字典顺序比较两个字符串

基本上,类似于以下(未测试的)比较函数:

bool is_not_digit(char c)
{
    return !std::isdigit(c);
}

bool numeric_string_compare(const std::string& s1, const std::string& s2)
{
    // handle empty strings...

    std::string::const_iterator it1 = s1.begin(), it2 = s2.begin();

    if (std::isdigit(s1[0]) && std::isdigit(s2[0])) {
        int n1, n2;
        std::stringstream ss(s1);
        ss >> n1;
        ss.clear();
        ss.str(s2);
        ss >> n2;

        if (n1 != n2) return n1 < n2;

        it1 = std::find_if(s1.begin(), s1.end(), is_not_digit);
        it2 = std::find_if(s2.begin(), s2.end(), is_not_digit);
    }

    return std::lexicographical_compare(it1, s1.end(), it2, s2.end());
}

编辑:当然,此算法仅在对字符串排序时有用,其中数字部分显示在字符串的开头。如果您处理的字符串中的数字部分可以出现在字符串中的任何位置,那么您需要更复杂的算法。有关更多信息,请参阅。

如果您的目标是Windows(XP+)并且能够将字符串转换为utf-16,则可以使用Shlwapi中的
strmplogical w
函数。有关详细信息,请参阅


否则,将在其collator中提供此功能。请参阅UCOL\u NUMERIC\u排序规则

这里有一个版本,它不转换为整数,因此适用于长字符串,而不管大小(int)

#包括
#包括
#包括
#包括
int numcmp(常量字符*a、常量字符*aend、常量字符*b、常量字符*bend)
{
对于(;;){
如果(a==aend){
如果(b==弯曲)
返回0;
返回-1;
}
如果(b==弯曲)
返回1;
如果(*a==*b){
++a、 ++b;
继续;
}
如果(!isdigit((无符号字符)*a)| |!isdigit((无符号字符)*b))
返回*a-*b;
//跳过两个字符串中的前导零
而(*a=='0'&&++a!=aend)
;
而(*b=='0'&&++b!=aend)
;
//跳到连续数字的末尾
常数char*aa=a;
while(a!=aend&&isdigit((未签名字符)*a))
++a;
std::ptrdiff_t alen=a-aa;
常数char*bb=b;
while(b!=bend&isdigit((无符号字符)*b))
++b;
标准:ptrdiff_t blen=b-bb;
如果(alen!=blen)
返回alen-blen;
//两个字符串中的连续位数相同
while(aa!=a){
如果(*aa!=*bb)
返回*aa-*bb;
++aa,++bb;
}
}
}
int numcmp(常数std::string&a,常数std::string&b)
{
返回nummp(a.data(),a.data()+a.size(),
b、 数据(),b.数据()+b.大小());
}
int numcmp(常量字符*a,常量字符*b)
{
返回numcmp(a,a+strlen(a),b,b+strlen(b));
}

+1因为您的代码处理的是其中一个开头包含数字,而另一个开头不包含数字的情况。
atoi
非常适合此目的,对于不以数字开头的字符串,您甚至不需要特殊代码(尽管它们将排序到开头)。或者
strotod
如果你想控制它。@Ben,是的,
atoi
将比
std::stringstream
更有效。FWIW,我编写了一个类似的函数,它使用
strotol
来,但从另一个角度来看,它不太正确-假设不比较数字时,直接比较字符是所需的顺序。转换为int(例如,通过atoi)时,假设数字的字符串表示形式可以成功转换为int。如果数字字符串较长,转换会溢出…当然,可能的重复取决于用例,但对于文件名,我实际上更喜欢XP之前的方式。我讨厌当软件试图变得过于聪明时,因为它开始把事情搞砸。。。尝试对>=XP中的十六进制文件名列表进行排序。
std::sort(string_array.begin(), string_array.end(), numeric_string_compare);
#include <cctype>
#include <cstddef>
#include <cstring>
#include <string>

int numcmp(const char *a, const char *aend, const char *b, const char *bend)
{
  for (;;) {
    if (a == aend) {
      if (b == bend)
        return 0;
      return -1;
    }
    if (b == bend)
      return 1;
    if (*a == *b) {
      ++a, ++b;
      continue;
    }
    if (!isdigit((unsigned char) *a) || !isdigit((unsigned char) *b))
      return *a - *b;

    // skip leading zeros in both strings
    while (*a == '0' && ++a != aend)
      ;
    while (*b == '0' && ++b != aend)
      ;

    // skip to end of the consecutive digits
    const char *aa = a;
    while (a != aend && isdigit((unsigned char) *a))
      ++a;
    std::ptrdiff_t alen = a - aa;

    const char *bb = b;
    while (b != bend && isdigit((unsigned char) *b))
      ++b;
    std::ptrdiff_t blen = b - bb;

    if (alen != blen)
      return alen - blen;

    // same number of consecutive digits in both strings
    while (aa != a) {
      if (*aa != *bb)
        return *aa - *bb;
      ++aa, ++bb;
    }
  }
}

int numcmp(const std::string& a, const std::string& b)
{
  return numcmp(a.data(), a.data() + a.size(),
                b.data(), b.data() + b.size());
}

int numcmp(const char *a, const char *b)
{
  return numcmp(a, a + strlen(a), b, b + strlen(b));
}