首页 > 解决方案 > C++ 对目录中的文件名进行排序

问题描述

我想对我拥有的代码提出一些建议。

我设法完成了我想做的事情,但我认为这不是程序员世界中“正确”的做法。

您能否以任何方式帮助我改进代码,如果有更好的方法,请也分享它们。

我有以以下格式命名的文件:

501.236.pcd

501.372.pcd

...

612.248.pcd 等

我想根据使用 C++ 的文件名将文件名按升序排列。

这是我使用的代码:

#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
#include <sstream>

using namespace std;
using namespace boost::filesystem;

int main()
{
    vector <string> str,parsed_str;
    path p("./fake_pcd");
    string delimiter = ".";
    string token,parsed_filename;
    size_t pos = 0;
    int int_filename;
    vector <int> int_dir;

    //insert filenames in the directory to a string vector
    for (auto i = directory_iterator(p); i != directory_iterator(); i++)
    {
        if (!is_directory(i->path())) //we eliminate directories in a list
        {
        str.insert(str.end(),i->path().filename().string());
        }
        else
            continue;
    }

    //parse each string element in the vector, split from each delimiter 
    //add each token together and convert to integer
    //put inside a integer vector 
    parsed_str = str;
    for (std::vector<string>::iterator i=parsed_str.begin(); i != parsed_str.end(); ++i)
    {
        cout << *i << endl;
        while ((pos = i->find(delimiter)) != string::npos) {    
        token = i->substr(0,pos);
        parsed_filename += token;
        i->erase(0, pos + delimiter.length());
    }

    int_filename = stoi(parsed_filename);
    int_dir.push_back(int_filename);

    parsed_filename = "";
    }

    cout << endl;

    parsed_str.clear();

    sort(int_dir.begin(), int_dir.end());

    //print the sorted integers
    for(vector<int>::const_iterator i=int_dir.begin(); i != int_dir.end(); i++) {
        cout << *i << endl;
    }

    //convert sorted integers to string and put them back into string vector
    for (auto &x : int_dir) {
        stringstream ss;
        ss << x;
        string y;
        ss >> y;
        parsed_str.push_back(y);
    }

    cout << endl;

    //change the strings so that they are like the original filenames  
    for(vector<string>::iterator i=parsed_str.begin(); i != parsed_str.end(); i++) {
        *i = i->substr(0,3) + "." + i->substr(3,3) + ".pcd";
        cout << *i << endl;
    }


}

这是输出,第一部分是 directory_iterator 获取它的顺序,第二部分是按整数排序的文件名,最后一部分是我将整数改回原始文件名格式的字符串的地方。

612.948.pcd
612.247.pcd
501.567.pcd
501.346.pcd
501.236.pcd
512.567.pcd
613.008.pcd
502.567.pcd
612.237.pcd
612.248.pcd

501236
501346
501567
502567
512567
612237
612247
612248
612948
613008

501.236.pcd
501.346.pcd
501.567.pcd
502.567.pcd
512.567.pcd
612.237.pcd
612.247.pcd
612.248.pcd
612.948.pcd
613.008.pcd

标签: c++linuxboost

解决方案


Boost Filesystem中的 Filtering 文件夹中获取一些提示,并且为了完全过度杀伤力:

Live On Coliru 使用 Boost(也在Wandbox.org 上

#include <boost/range/adaptors.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/filesystem.hpp>
#include <iostream>
#include <optional>
#include <set>

namespace fs = boost::filesystem;

namespace {
    using Path = fs::path;

    struct Ranked {
        std::optional<int> rank;
        Path path;
        explicit operator bool() const { return rank.has_value(); }
        bool operator<(Ranked const& rhs) const { return rank < rhs.rank; }
    };

    static Ranked rank(Path const& p) {
        if (p.extension() == ".pcd") {
            auto stem = p.stem().native();

            std::string digits;
            using namespace boost::spirit::x3;
            if (phrase_parse(begin(stem), end(stem), +digit >> eoi, punct, digits))
                return { std::stoul(digits), p };
        }
        return { {}, p };
    }
}

int main() {
    using namespace boost::adaptors;

    auto dir = boost::make_iterator_range(fs::directory_iterator("."), {}) 
         | transformed(std::mem_fn(&fs::directory_entry::path))
         | transformed(rank)
         ;

    std::multiset<Ranked> index(begin(dir), end(dir));

    for (auto& [rank, path] : index) {
        std::cout << rank.value_or(-1) << "\t" << path << "\n";
    }
}

印刷:

-1  "./main.cpp"
-1  "./a.out"
501008  "./501.008.pcd"
501236  "./501.236.pcd"
501237  "./501.237.pcd"
501247  "./501.247.pcd"
501248  "./501.248.pcd"
501346  "./501.346.pcd"
501567  "./501.567.pcd"
501948  "./501.948.pcd"
502008  "./502.008.pcd"
502236  "./502.236.pcd"
502237  "./502.237.pcd"
502247  "./502.247.pcd"
502248  "./502.248.pcd"
502346  "./502.346.pcd"
502567  "./502.567.pcd"
502948  "./502.948.pcd"
512008  "./512.008.pcd"
512236  "./512.236.pcd"
512237  "./512.237.pcd"
512247  "./512.247.pcd"
512248  "./512.248.pcd"
512346  "./512.346.pcd"
512567  "./512.567.pcd"
512948  "./512.948.pcd"
612008  "./612.008.pcd"
612236  "./612.236.pcd"
612237  "./612.237.pcd"
612247  "./612.247.pcd"
612248  "./612.248.pcd"
612346  "./612.346.pcd"
612567  "./612.567.pcd"
612948  "./612.948.pcd"
613008  "./613.008.pcd"
613236  "./613.236.pcd"
613237  "./613.237.pcd"
613247  "./613.247.pcd"
613248  "./613.248.pcd"
613346  "./613.346.pcd"
613567  "./613.567.pcd"
613948  "./613.948.pcd"

奖金:无助推解决方案

由于文件系统库已标准化并使用 Rangev3:

Live On Wandbox

#include <filesystem>
#include <iostream>
#include <map>
#include <optional>
#include <range/v3/action/remove_if.hpp>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/transform.hpp>

namespace fs = std::filesystem;

namespace {
    using namespace ranges;

    using Ranked = std::pair<std::optional<int>, fs::path>;
    bool has_rank(Ranked const& v) { return v.first.has_value(); }

    static Ranked ranking(fs::path const& p) {
        if (p.extension() == ".pcd") {
            auto stem = p.stem().native();
            auto non_digit = [](uint8_t ch) { return !std::isdigit(ch); };
            stem |= actions::remove_if(non_digit);
            return { std::stoul(stem), p };
        }
        return { {}, p };
    }
}

int main() {
    using It = fs::directory_iterator;

    for (auto&& [rank, path] : subrange(It("."), It())
            | views::transform(std::mem_fn(&fs::directory_entry::path))
            | views::transform(ranking)
            | views::filter(has_rank)
            | to<std::multimap>())
    {
        std::cout << rank.value_or(-1) << "\t" << path << "\n";
    }
}

打印例如

501236  "./501.236.pcd"
501346  "./501.346.pcd"
501567  "./501.567.pcd"
502567  "./502.567.pcd"

推荐阅读