Frage

Ich bin Sortierfolgen, die aus Text und Zahlen bestehen. Ich mag die Art, die Anzahl Teile als Zahlen sortieren, nicht alphanumerische.

Zum Beispiel ich will: abc1def, ..., abc9def, abc10def

statt: abc10def, abc1def, ..., abc9def

Kennt jemand einen Algorithmus für diese (insbesondere in C ++)

Danke

War es hilfreich?

Lösung

Ich fragte genau diese Frage (obwohl in Java) und bekam deutete auf http://www.davekoelle.com/alphanum.html die hat einen Algorithmus und Implementierungen es in vielen Sprachen.

Andere Tipps

Dies ist als natürliche Sortierung bekannt. Es gibt einen Algorithmus hier dass sieht vielversprechend aus.

Achten Sie auf Probleme mit Nicht-ASCII-Zeichen (siehe Jeffs Blog-Eintrag zu diesem Thema).

Mehrere natürliche Art Implementierungen für C ++ zur Verfügung. Ein kurzer Überblick:

  • natural_sort<> - basierend auf Boost.Regex.
    • In meinen Tests, es ist etwa 20-mal langsamer als andere Optionen.
  • Dirk Jagdmann alnum.hpp , basierend auf Dave Koelle der alphanum Algorithmus
    • Mögliche integer overlow Ausgaben für Werte über MAXINT
  • Martin Pool natsort - in C geschrieben, aber trivialer verwendbar von C ++.
    • Die einzige C / C ++ Implementierung ich gesehen habe einen Fall unempfindliche Version anbieten zu können, die eine hohe Priorität für eine „natürliche“ Art zu sein scheinen.
    • Wie die anderen Implementierungen, ist es nicht wirklich Dezimalpunkten analysieren, aber es hat Sonderfall führende Nullen (alles mit einer führenden 0 angenommen wird, um eine Fraktion zu sein), die ein wenig seltsam, aber potentiell nützlich ist.
    • PHP verwendet diesen Algorithmus.

Teilweise Umbuchung meine andere Antwort :

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() Funktion:

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

Verbrauch:

std::vector<std::string> str;
str.push_back("abc1def");
str.push_back("abc10def");
...
std::sort(str.begin(), str.end(), compareNat);

Zur Lösung, was im Wesentlichen ein Parsing Problem einer Zustandsmaschine (aka endliche Automaten ) ist der Weg zu gehen. Unzufrieden mit den oben genannten Lösungen schrieb ich einen einfachen One-Pass frühen bail-out-Algorithmus, der C Schläge / C ++ Varianten oben in Bezug auf der Leistung vorgeschlagen, leidet nicht an numerischen Datentyp Überlauffehler, und ist leicht zu ändern Fall Unempfindlichkeit hinzufügen, wenn erforderlich .

können Quellen hier werden

// -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;
}

Ich bin nicht ganz sicher, ob es Sie wollen, wie auch immer, können Sie einen Versuch: -)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top