C ++ Сортировка имен файлов в каталоге - PullRequest
1 голос
/ 16 апреля 2020

Я хотел бы получить совет по поводу кода, который у меня есть.

Мне удалось добиться того, чего я хотел, но я не думаю, что это «правильный» способ сделать это в мире программистов.

Не могли бы вы помочь мне улучшить код любыми способами, а также, если есть более эффективные способы сделать это, пожалуйста, поделитесь ими.

У меня есть файлы, названные в формате:

501.236.pcd

501.372.pcd

...

612.248.pcd et c.

Я хотел указать имена файлов в порядке возрастания в соответствии с именами файлов с использованием 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

1 Ответ

0 голосов
/ 20 апреля 2020

Взяв несколько подсказок, например, Фильтрация папок в файловой системе Boost и в интересах общего перебора:

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"
...