Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用Qt对文件名进行自然排序_C++_Qt_Natural Sort - Fatal编程技术网

C++ 使用Qt对文件名进行自然排序

C++ 使用Qt对文件名进行自然排序,c++,qt,natural-sort,C++,Qt,Natural Sort,我正在使用QDir::entryList()阅读目录内容。其中的文件名的结构如下所示: index_randomNumber.png 我需要按索引对它们进行排序,这是Windows资源管理器对文件进行排序的方式,以便 0_0815.png 1_4711.png 2_2063.png ... 而不是按QDir::Name排序给我的结果: 0_0815.png 10000_6661.png 10001_7401.png ... Qt中是否有实现这一点的内置方法?如果没有,在什么地方实现它?是的

我正在使用
QDir::entryList()
阅读目录内容。其中的文件名的结构如下所示:

index_randomNumber.png
我需要按
索引
对它们进行排序,这是Windows资源管理器对文件进行排序的方式,以便

0_0815.png
1_4711.png
2_2063.png
...
而不是按
QDir::Name
排序给我的结果:

0_0815.png
10000_6661.png
10001_7401.png
...
Qt中是否有实现这一点的内置方法?如果没有,在什么地方实现它?

是的,这是可能的

为此,您需要在构造
QDir
时指定标志。对象构造函数是

 QDir(const QString & path, const QString & nameFilter, SortFlags sort = SortFlags( Name | IgnoreCase ), Filters filters = AllEntries)
你也可以使用

QDir dir;
dir.setSorting(QDir::LocaleAware);

在Qt5.2之前,Qt没有自然排序实现,请参阅

自Qt5.2以来,在启用时有一个允许自然排序的函数。

inline int findNumberPart(const QString&sIn)
inline int findNumberPart(const QString& sIn)
{
  QString s = "";
  int i = 0;
  bool isNum = false;
  while (i < sIn.length())
  {
    if (isNum)
    {
      if (!sIn[i].isNumber())
        break;
      s += sIn[i];
    }
    else
    {
      if (sIn[i].isNumber())
        s += sIn[i];
    }
    ++i;
  }
  if (s == "")
    return 0;
  return s.toInt();
}

bool naturalSortCallback(const QString& s1, const QString& s2)
{
  int idx1 = findNumberPart(s1);
  int idx2 = findNumberPart(s2);
  return (idx1 < idx2);
}

int main(int argc, char *argv[])
{
  QCoreApplication a(argc, argv);

  QDir dir(MYPATH);
  QStringList list = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
  qSort(list.begin(), list.end(), naturalSortCallback);
  foreach(QString s, list)
    qDebug() << s << endl;

  return a.exec();
}
{ QString s=“”; int i=0; bool-isNum=false; 而(iqDebug()Qt本机不支持自然排序,但它可以非常容易地实现。例如,这可以用于对
QStringList
进行排序:

struct naturalSortCompare {

    inline bool isNumber(QChar c) {
        return c >= '0' && c <= '9';
    }

    inline bool operator() (const QString& s1, const QString& s2) {
        if (s1 == "" || s2 == "") return s1 < s2;

        // Move to the first difference between the strings
        int startIndex = -1;
        int length = s1.length() > s2.length() ? s2.length() : s1.length();
        for (int i = 0; i < length; i++) {
            QChar c1 = s1[i];
            QChar c2 = s2[i];
            if (c1 != c2) {
                startIndex = i;
                break;
            }
        }

        // If the strings are the same, exit now.
        if (startIndex < 0) return s1 < s2;

        // Now extract the numbers, if any, from the two strings.
        QString sn1;
        QString sn2;
        bool done1 = false;
        bool done2 = false;
        length = s1.length() < s2.length() ? s2.length() : s1.length();

        for (int i = startIndex; i < length; i++) {
            if (!done1 && i < s1.length()) {
                if (isNumber(s1[i])) {
                    sn1 += QString(s1[i]);
                } else {
                    done1 = true;
                }
            }

            if (!done2 && i < s2.length()) {
                if (isNumber(s2[i])) {
                    sn2 += QString(s2[i]);
                } else {
                    done2 = true;
                }
            }

            if (done1 && done2) break;
        }

        // If none of the strings contain a number, use a regular comparison.
        if (sn1 == "" && sn2 == "") return s1 < s2;

        // If one of the strings doesn't contain a number at that position,
        // we put the string without number first so that, for example,
        // "example.bin" is before "example1.bin"
        if (sn1 == "" && sn2 != "") return true;
        if (sn1 != "" && sn2 == "") return false;

        return sn1.toInt() < sn2.toInt();
    }

};
如果要使用对返回的条目列表中的条目进行排序,可以使用以下方法对结果进行排序:


这并不是对问题本身的回答,而是一些一般性的信息,以帮助那些偶然发现这一点的人了解如何“自然排序”

首先,这是不可能的。“正确的”自然排序取决于上下文,而上下文是“真正的”人工智能所无法具备的。例如,如果我有一堆数字和字母混合的文件名,而这些文件名的某些部分恰好匹配
[0-9a-f]
,那是十六进制数吗?是“1500”与“1500”相同,或者“1”和“500”是单独的数字?是“2019/06/07”在“2019/07/06”之前还是之后?是“1.21”还是“1.5”?(提示:最后一个取决于它们是十进制数字还是语义版本号。)

“解决”这个问题需要约束它;决定我们只处理特定的情况,而超出这些限制的任何事情都只会产生一个“错误”的答案。(幸运的是,OP的问题似乎已经满足了通常的约束。)


这就是说,我相信
QCollator
通常工作得很好(同样,它并不“真正”工作,但它在普遍接受的约束条件下取得了成功)。在“自己的解决方案”部门,也可以看一看,这是我编写的对不同(不是
QCollator
)算法的qtapi改进。(撰写本文时不支持区分大小写,但欢迎使用补丁!)我花了大量精力让它“正确”解析数字,甚至处理任意长度的数字和非BMP数字。

谢谢,这改变了结果,但没有解决问题。现在文件名的排序方式是:
0\u 0815,1\u 4711,10\u 8234,100\u 5978,
。您可能需要自己对文件名进行排序。尝试
dir.setSorting(QDir::Name);
dir.setSorting(QDir::LocaleAware | QDir::Name);
。抱歉,我现在无法检查,我必须检查leave@elmigranto我想是这样,但一般来说,Qt提供了一种获得与本机应用程序完全相同的结果的方法。对不起,这对我不起作用。
QCollator
允许您设置数字模式;
QDir::setSorting()
不行。不确定此函数在所有情况下都能工作,因为它只是从字符串中提取数字,而不检查数字的实际位置。例如,它会将“aaa2,bbb1”排序为“bbb1,aaa2”,这是不正确的。此实现似乎有错误。示例输入字符串:
f3.ext、f10.ext、f100.ext、f1000.ext、f15.ext
。我认为它首先会升级到字符不再相等的程度是有问题的,因为这忽略了有价值的数字比较。我发现我需要始终使用尽可能多的数字rs尽可能多。实际上不需要lambda,因为QCollator有一个未记录的
操作符()
std::sort(entryList.begin(),entryList.end(),collator);
应该足够好了。我认为这在文档的下一行中是隐含的“QCollator对象可以与基于模板的排序算法(如std::sort)一起用于对qstring列表进行排序。”显然这是正确的答案,但由于Romário实际提供了代码,他必须获得投票!
std::sort(stringList.begin(), stringList.end(), naturalSortCompare());
dir.setFilter(QDir::Files | QDir::NoSymLinks);
dir.setSorting(QDir::NoSort);  // will sort manually with std::sort

auto entryList = dir.entryList();

QCollator collator;
collator.setNumericMode(true);

std::sort(
    entryList.begin(),
    entryList.end(),
    [&collator](const QString &file1, const QString &file2)
    {
        return collator.compare(file1, file2) < 0;
    });
std::sort(entryList.begin(), entryList.end(), collator);