17

テキストと数字で構成される文字列を並べ替えています。並べ替えで、数字の部分を英数字ではなく数字として並べ替えたい。

たとえば、次のようにします:abc1def、...、abc9def、abc10def

代わりに:abc10def、abc1def、...、abc9def

誰かがこれのためのアルゴリズムを知っていますか(特にc ++で)

ありがとう

4

9 に答える 9

8

C++ 用のいくつかの自然な並べ替えの実装が利用可能です。簡単なレビュー:

  • natural_sort<>- Boost.Regex に基づく。
    • 私のテストでは、他のオプションよりも約 20 倍遅いです。
  • Dave Koelle のalphanum アルゴリズムalnum.hppに基づくDirk Jagdmann の。
    • MAXINT を超える値の潜在的な整数過小問題
  • Martin Pool's natsort- C で書かれていますが、C++ から簡単に使用できます。
    • 私が見た唯一の C/C++ 実装は、大文字と小文字を区別しないバージョンを提供しています。これは、「自然な」ソートの優先度が高いようです。
    • 他の実装と同様に、実際には小数点を解析しませんが、特殊なケースの先行ゼロ (先頭に 0 があるものはすべて分数と見なされます) を処理します。これは少し奇妙ですが、潜在的に有用です。
    • PHP はこのアルゴリズムを使用します。
于 2014-11-05T19:43:49.840 に答える
6

これは自然順として知られています。ここには有望に見えるアルゴリズムがあります。

非ASCII文字の問題に注意してください(この件に関するJeffのブログエントリを参照してください)。

于 2009-03-13T11:18:54.853 に答える
2

私の別の答えを部分的に再投稿します:

bool compareNat(const std::string& a, const std::string& b){
    if (a.empty())
        return true;
    if (b.empty())
        return false;
    if (std::isdigit(a[0]) && !std::isdigit(b[0]))
        return true;
    if (!std::isdigit(a[0]) && std::isdigit(b[0]))
        return false;
    if (!std::isdigit(a[0]) && !std::isdigit(b[0]))
    {
        if (a[0] == b[0])
            return compareNat(a.substr(1), b.substr(1));
        return (toUpper(a) < toUpper(b));
        //toUpper() is a function to convert a std::string to uppercase.
    }

    // Both strings begin with digit --> parse both numbers
    std::istringstream issa(a);
    std::istringstream issb(b);
    int ia, ib;
    issa >> ia;
    issb >> ib;
    if (ia != ib)
        return ia < ib;

    // Numbers are the same --> remove numbers and recurse
    std::string anew, bnew;
    std::getline(issa, anew);
    std::getline(issb, bnew);
    return (compareNat(anew, bnew));
}

toUpper()関数:

std::string toUpper(std::string s){
    for(int i=0;i<(int)s.length();i++){s[i]=toupper(s[i]);}
    return s;
    }

使用法:

std::vector<std::string> str;
str.push_back("abc1def");
str.push_back("abc10def");
...
std::sort(str.begin(), str.end(), compareNat);
于 2015-11-15T20:36:53.183 に答える
-1
// -1: s0 < s1; 0: s0 == s1; 1: s0 > s1
static int numericCompare(const string &s0, const string &s1) {
    size_t i = 0, j = 0;
    for (; i < s0.size() && j < s1.size();) {
        string t0(1, s0[i++]);
        while (i < s0.size() && !(isdigit(t0[0]) ^ isdigit(s0[i]))) {
            t0.push_back(s0[i++]);
        }
        string t1(1, s1[j++]);
        while (j < s1.size() && !(isdigit(t1[0]) ^ isdigit(s1[j]))) {
            t1.push_back(s1[j++]);
        }
        if (isdigit(t0[0]) && isdigit(t1[0])) {
            size_t p0 = t0.find_first_not_of('0');
            size_t p1 = t1.find_first_not_of('0');
            t0 = p0 == string::npos ? "" : t0.substr(p0);
            t1 = p1 == string::npos ? "" : t1.substr(p1);
            if (t0.size() != t1.size()) {
                return t0.size() < t1.size() ? -1 : 1;
            }
        }
        if (t0 != t1) {
            return t0 < t1 ? -1 : 1;
        }
    }
    return i == s0.size() && j == s1.size() ? 0 : i != s0.size() ? 1 : -1;
}

あなたがそれを望んでいるかどうかはよくわかりませんが、とにかく試してみてください:-)

于 2011-01-09T15:00:42.437 に答える