You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt C++中实现文件名按整数序列自然排序的问题求助

Qt实现文件名自然排序(QListWidget)

默认QListWidget的排序是字典序,会导致image1.png、image10.png、image100.png这类不符合数字逻辑的排序结果。要实现按文件名中数字递增的自然排序,可通过以下两种方式解决:

方法一:先对QStringList进行自然排序再添加到列表

  1. 定义自然排序的比较函数,提取文件名中的数字部分进行比较:
bool naturalSort(const QString &a, const QString &b) {
    // 提取文件名(不含后缀)
    QString nameA = a.split('.').first();
    QString nameB = b.split('.').first();
    
    // 匹配文件名中的数字序列
    QRegularExpression numRegex(R"(\d+)");
    QRegularExpressionMatch numMatchA = numRegex.match(nameA);
    QRegularExpressionMatch numMatchB = numRegex.match(nameB);
    
    int numA = numMatchA.hasMatch() ? numMatchA.captured().toInt() : 0;
    int numB = numMatchB.hasMatch() ? numMatchB.captured().toInt() : 0;
    
    // 先按数字大小排序,数字相同则按原字符串字典序
    if (numA != numB) {
        return numA < numB;
    }
    return a < b;
}
  1. 修改原代码,收集完所有文件名后执行排序,再添加到QListWidget:
void QtWidgetsApplication::displayImagesList() {
    // 注意路径中的反斜杠需要转义,或使用正斜杠
    QDirIterator it(QStringLiteral("C:\\Users\\Documents\\Visual Studio 2015\\Projects\\cas\\images"),
        QStringList() << "*.png", QDir::Files, QDirIterator::Subdirectories);
    
    QStringList faList;
    while (it.hasNext()) {
        QFileInfo file(it.next());
        faList.append(file.fileName());
        _files.push_back(file.fileName());
    }
    
    // 对文件名列表执行自然排序
    std::sort(faList.begin(), faList.end(), naturalSort);
    
    ui.images->addItems(faList);
    ui.images->setSortingEnabled(true);
    ui.images->setMinimumWidth(ui.images->sizeHintForColumn(0));
}

方法二:给QListWidget设置自定义排序代理

通过继承QSortFilterProxyModel重写排序规则,让列表控件直接支持自然排序:

  1. 定义自定义代理类:
#include <QSortFilterProxyModel>
#include <QRegularExpression>

class NaturalSortProxyModel : public QSortFilterProxyModel {
    Q_OBJECT
protected:
    bool lessThan(const QModelIndex &left, const QModelIndex &right) const override {
        QString leftStr = sourceModel()->data(left).toString();
        QString rightStr = sourceModel()->data(right).toString();
        
        QString nameLeft = leftStr.split('.').first();
        QString nameRight = rightStr.split('.').first();
        
        QRegularExpression numRegex(R"(\d+)");
        QRegularExpressionMatch numMatchLeft = numRegex.match(nameLeft);
        QRegularExpressionMatch numMatchRight = numRegex.match(nameRight);
        
        int numLeft = numMatchLeft.hasMatch() ? numMatchLeft.captured().toInt() : 0;
        int numRight = numMatchRight.hasMatch() ? numMatchRight.captured().toInt() : 0;
        
        if (numLeft != numRight) {
            return numLeft < numRight;
        }
        return leftStr < rightStr;
    }
};
  1. 在列表初始化时设置代理:
void QtWidgetsApplication::displayImagesList() {
    QDirIterator it(QStringLiteral("C:\\Users\\Documents\\Visual Studio 2015\\Projects\\cas\\images"),
        QStringList() << "*.png", QDir::Files, QDirIterator::Subdirectories);
    
    QStringList faList;
    while (it.hasNext()) {
        QFileInfo file(it.next());
        faList.append(file.fileName());
        _files.push_back(file.fileName());
    }
    
    ui.images->addItems(faList);
    
    // 创建并设置排序代理
    NaturalSortProxyModel *sortProxy = new NaturalSortProxyModel(this);
    sortProxy->setSourceModel(ui.images->model());
    ui.images->setModel(sortProxy);
    
    ui.images->setSortingEnabled(true);
    ui.images->sortItems(Qt::AscendingOrder);
    ui.images->setMinimumWidth(ui.images->sizeHintForColumn(0));
}

注意事项

  • 路径中的反斜杠必须转义(写成\\),或直接使用正斜杠/避免转义问题;
  • 若文件名包含多段数字,可扩展比较函数以支持多段数字的依次比较;
  • Qt 5及以上版本推荐使用std::sort替代qSort。

内容的提问来源于stack exchange,提问作者Cassey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 11:25:43