C++中自然排序的目录文件名

Abh*_*nav 7 c c++ linux sorting directory

我有一个目录列表,我想要检索文件名并将它们放在一个字符串向量中,以便它们以"自然"的方式排序.例如{ "10.txt" "0.txt" "2.txt" "1.m" "Jan12" "July13.txt" "Nov25.txt" "Jane" "John" }应该{"0.txt" "1.m" "2.txt" "10.txt" "Jan12" "July13.txt" "Nov25.txt" "Jane" "John" }.最简单的方法是什么?

在阐述"自然",我们假设从号码的部分组成的字符串(N)和文本(T)这样...(N)(T)...,那么对于...(N1)(T1)......(N2)(T2)...(N1<N2) (<) (T1<T2),其中 (<)暗示了正确的长期左边项优先.在这种情况下,如果数字在字符串中处于相同位置,则数字优先于文本字段,即1.z (<) 1_t.txt.

是否已经有一个库函数来对字母数字字符串或目录条目进行那种排序?

期望的文件顺序.文件名将存储在字符串向量中.

Abhinav@Abhinav-PC /cygdrive/c/AbhinavSamples/shell
$ ls -lv
total 8
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:51 1.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:55 1_t.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:50 3.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:51 4.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:53 10.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:56 10_t.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:56 13.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:53 20.txt

**Simple Sort**
Abhi@Abhi-PC /cygdrive/c/AbhinavSamples/shell
$ ls -l
total 8
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:51 1.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:53 10.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:56 10_t.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:56 13.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:55 1_t.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:53 20.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:50 3.txt
-rw-r--r--+ 1 Abhinav None 2 Mar 17 00:51 4.txt
Run Code Online (Sandbox Code Playgroud)

Chr*_*mer 11

你需要一个能够在两个字符串之间进行自然比较的函数.之后,您可以使用std::sort比较函数作为第三个参数(如@chac已经指出的那样).在下面我尝试以递归方式实现这样的函数.注意,它可以处理任意文件名,这些文件名不需要以数字部分开头并以字符串部分结尾:

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 (std::toupper(a[0]) == std::toupper(b[0]))
            return compareNat(a.substr(1), b.substr(1));
        return (std::toupper(a[0]) < std::toupper(b[0]));
    }

    // 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));
}
Run Code Online (Sandbox Code Playgroud)

这是一个简单的测试用例:

#include <iostream> // std::cout
#include <string>
#include <algorithm> // std::sort, std::copy
#include <iterator> // std::ostream_iterator
#include <sstream> // std::istringstream
#include <vector>
#include <cctype> // std::isdigit

int main()
{
    std::vector<std::string> str;
    str.push_back("20.txt");
    str.push_back("10.txt");
    str.push_back("1.txt");
    str.push_back("z2.txt");
    str.push_back("z10.txt");
    str.push_back("z100.txt");
    str.push_back("1_t.txt");

    std::sort(str.begin(), str.end(), compareNat);
    std::copy(str.begin(), str.end(),
              std::ostream_iterator<std::string>(std::cout, "\n"));
}
Run Code Online (Sandbox Code Playgroud)

结果是:

1.txt
1_t.txt
10.txt
20.txt
z2.txt
z10.txt
z100.txt
Run Code Online (Sandbox Code Playgroud)


sir*_*rge 7

有一个函数在glibc 中完全符合你的要求.不幸的是它是C,而不是C++,所以如果你可以忍受这里是最简单的解决方案"开箱即用",没有重新实现任何东西和重新发明轮子.顺便说一句:这与ls -lv实施完全一致.其中最重要的部分是为您自然排序versionsort功能.它在这里用作比较函数.下面的简单示例打印当前目录中按您的意愿排序的所有文件/目录.scandir

#define _GNU_SOURCE
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    struct dirent **namelist;
    int n,i;

    n = scandir(".", &namelist, 0, versionsort);
    if (n < 0)
        perror("scandir");
    else
    {
        for(i =0 ; i < n; ++i)
        {
            printf("%s\n", namelist[i]->d_name);
            free(namelist[i]);
        }
        free(namelist);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)