c++ - 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
解决方案
从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:
#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"
推荐阅读
- xamarin.forms - 如何在 ViewRenderer 中访问 ViewWillAppear/ViewDidDisappear
? - amazon-web-services - Why does AWS RDS still shows burst balance 0 with disk size 2TB gp2?
- javascript - React 没有使用 e.target.getAttribute() 方法获取自定义属性
- python - 谁能帮我解释这个 python 程序的第 2 行?
- java - 在 Spring 中将 XML 文件上传到 Java 后端
- python - 从交互式图表中抓取 JSON 数据 - 额外数据错误 `json.load()`
- bootstrap-4 - Bootstrap:行中的元素未与页面左侧对齐
- c++ - 我想通过 Arduino 读取 ML-NTC2 温度传感器的值。但我得到错误:从'char*'到'const uint8_t*'的无效转换
- apache-spark - 在启用了推测的情况下,如何在 Spark 中管理写入?
- numpy - 从包含 ma.masked 的列表创建屏蔽数组