Pergunta

Eu estou classificando strings que são compostos de texto e números. Eu quero a classificação para classificar as peças número como números, não alfanumérico.

Por exemplo, eu quero: abc1def, ..., abc9def, abc10def

em vez de: abc10def, abc1def, ..., abc9def

Alguém sabe um algoritmo para isso (em particular em c ++)

Graças

Foi útil?

Solução

esta pergunta exata (embora em Java) e foi apontado http://www.davekoelle.com/alphanum.html que tem um algoritmo e implementações de que em muitas línguas.

Outras dicas

Isto é conhecido como ordenação natural. Há um algoritmo aqui que parece promissor.

Tenha cuidado de problemas com caracteres não-ASCII (ver Jeff blogue entrada sobre o assunto).

Várias implementações classificação natural para C ++ estão disponíveis. Uma revisão breve:

  • natural_sort<> - com base em Boost.Regex.
    • Em meus testes, é cerca de 20 vezes mais lento do que outras opções.
  • alnum.hpp , baseado em Dave Koelle alphanum algoritmo
    • inteiro Potencial overlow questões para valores mais MAXINT
  • O Martin Piscina natsort - escrito em C, mas trivialmente utilizável a partir C ++.
    • A única aplicação C / C ++ que eu vi para oferecer uma versão insensível caso, o que parece ser uma alta prioridade para um "natural" tipo.
    • Como as outras implementações, que na verdade não de análise pontos decimais, mas faz caso especial zeros à esquerda (qualquer coisa com um 0 é assumido como sendo uma fração), que é um pouco estranho, mas potencialmente útil.
    • PHP usa este algoritmo.

minha outra resposta :

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

função toUpper():

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

Uso:

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

Para resolver o que é essencialmente um problema ao analisar uma máquina de estado (aka finito estado autômato ) é o caminho a percorrer. Insatisfeito com as soluções acima i escreveu um algoritmo de bail-out simples de uma passagem mais cedo que bate C / C ++ variantes sugerido acima, em termos de desempenho, não sofre de erros tipo de dados de estouro numéricos, e é fácil de modificar para adicionar caso insensibilidade, se necessário .

fontes pode ser encontrada href="https://www.o-rho.com/naturalsort" aqui

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

Eu não estou muito certo se é que você quer, de qualquer maneira, você pode ter uma tentativa: -)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top