我想按照人类对它们进行排序的方式对字母数字字符串进行排序。即,“A2”出现在“A10”之前,“a”肯定出现在“Z”之前!没有编写迷你解析器,有什么办法吗?理想情况下,它也会将“A1B1”放在“A1B10”之前。我看到问题"Natural (human alpha-numeric) sort in Microsoft SQL 2005"有一个可能的答案,但它使用了各种库函数,"Sorting Strings for Humans with IComparer"也是如此。
以下是目前失败的测试用例:
#include <set>
#include <iterator>
#include <iostream>
#include <vector>
#include <cassert>
template <typename T>
struct LexicographicSort {
inline bool operator() (const T& lhs, const T& rhs) const{
std::ostringstream s1,s2;
s1 << toLower(lhs); s2 << toLower(rhs);
bool less = s1.str() < s2.str();
//Answer: bool less = doj::alphanum_less<std::string>()(s1.str(), s2.str());
std::cout<<s1.str()<<" "<<s2.str()<<" "<<less<<"\n";
return less;
}
inline std::string toLower(const std::string& str) const {
std::string newString("");
for (std::string::const_iterator charIt = str.begin();
charIt!=str.end();++charIt) {
newString.push_back(std::tolower(*charIt));
}
return newString;
}
};
int main(void) {
const std::string reference[5] = {"ab","B","c1","c2","c10"};
std::vector<std::string> referenceStrings(&(reference[0]), &(reference[5]));
//Insert in reverse order so we know they get sorted
std::set<std::string,LexicographicSort<std::string> > strings(referenceStrings.rbegin(), referenceStrings.rend());
std::cout<<"Items:\n";
std::copy(strings.begin(), strings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
std::vector<std::string> sortedStrings(strings.begin(), strings.end());
assert(sortedStrings == referenceStrings);
}
答案 0 :(得分:5)
答案 1 :(得分:2)
这实际上取决于“解析器”的含义。如果你想避免编写解析器,我认为你应该利用库函数。
isalnum
获取每个字符串的下一个字母数字序列,并对+
或-
进行回溯检查(如果它是数字)。使用strtold
就地查找数字子序列的结尾。strcoll
比较当前区域设置中的字母顺序。strtold
比较当前区域设置中的数字子序列。strcmp
断绝关系。此算法在比较超出long double
精度的数字字符串时存在一些缺点。
答案 2 :(得分:0)
如果没有编写迷你解析器,有没有办法做到这一点?我认为答案是否定的。但编写解析器并不是那么难。我不久前必须这样做才能对我们公司的股票编号进行排序。基本上只需扫描数字并将其转换为数组。检查每个角色的“类型”:alpha,number,也许你还有其他你需要处理的特殊角色。就像我必须特别对待连字符,因为我们希望A-B-C在AB-A之前排序。然后开始剥离字符。只要它们与第一个字符的类型相同,它们就会进入同一个桶。类型更改后,您将开始将它们放在不同的存储桶中。那么你还需要一个比较函数来逐桶比较。当两个桶都是alpha时,你只需进行正常的alpha比较。当两者都是数字时,将两者都转换为整数并进行整数比较,或者将较短的数据填充为较长或等效的长度。当它们是不同的类型时,你需要一个规则来比较那些比较,就像A-A在A-1之前或之后出现一样?
这不是一项微不足道的工作,你必须为所有可能出现的奇怪案件制定规则,但我认为你可以在几个小时的工作中将它们结合在一起。
答案 3 :(得分:0)
没有任何解析,就没有办法比较人类的书写数字(高值首先被剥离前导零)和普通字符作为同一个字符串的一部分。
虽然解析不需要非常复杂。一个简单的哈希表来处理区分大小写和剥离特殊字符('A'='a'= 1,'B'='b'='2,...或'A'= 1,'a' = 2,'B'= 3,...,' - '= 0(strip)),将您的字符串重新映射到散列值数组,然后截断数字情况(如果遇到一个数字,最后一个字符是a number,将最后一个数字乘以10并将当前值添加到其中。)
从那里开始,正常排序。