【问题标题】:C++ Sorting Filenames In A DirectoryC++ 对目录中的文件名进行排序
【发布时间】:2020-07-30 01:11:06
【问题描述】:

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

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

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

我有以下格式的文件:

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

【问题讨论】:

  • 对于这个例子,似乎直接将文件名作为字符串比较就可以了。
  • 如果您正在寻找代码审查,这个地方是Code Review

标签: c++ linux boost


【解决方案1】:

从例如Filtering folders in Boost Filesystem 并且为了完全矫枉过正:

Live On Coliru 使用 Boost(也称为 On 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"

【讨论】:

    猜你喜欢
    • 2011-07-04
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    • 2018-04-29
    • 2015-04-15
    • 1970-01-01
    • 2012-07-27
    • 1970-01-01
    相关资源
    最近更新 更多