Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I normalize a filepath in C++ using std::filesystem::path?

Tags:

c++

I am trying to convert a path string to a normalized (neat) format where any number of directory separators "\\" or "/" is converted to one default directory separator:

R"(C:\\temp\\Recordings/test)" -> R"(C:\temp\Recordings\test)"

Code:

#include <string>
#include <vector>
#include <iostream>
#include <filesystem>

std::string normalizePath(const std::string& messyPath) {
    std::filesystem::path path(messyPath);
    std::string npath = path.make_preferred().string();
    return npath;
}

int main()
{
    std::vector<std::string> messyPaths = { R"(C:\\temp\\Recordings/test)", R"(C://temp\\Recordings////test)" };
    std::string desiredPath = R"(C:\temp\Recordings\test)";
    for (auto messyPath : messyPaths) {
        std::string normalizedPath = normalizePath(messyPath);
        if (normalizedPath != desiredPath) {
            std::cout << "normalizedPath: " << normalizedPath << " != " << desiredPath << std::endl;
        }
    }
    std::cout << "Press any key to continue.\n";
    int k;
    std::cin >> k;
}

Output on Windows VS2019 x64:

normalizedPath: C:\\temp\\Recordings\test != C:\temp\Recordings\test
normalizedPath: C:\\temp\\Recordings\\\\test != C:\temp\Recordings\test

Reading the std::filepath documentation:

A path can be normalized by following this algorithm:
1. If the path is empty, stop (normal form of an empty path is an empty path)
2. Replace each directory-separator (which may consist of multiple slashes) with a single path::preferred_separator.
... 

Great, but which library function does this? I do not want to code this myself.

like image 216
Andy Avatar asked Oct 22 '25 00:10

Andy


2 Answers

As answered by bolov:

std::string normalizePath(const std::string& messyPath) {
    std::filesystem::path path(messyPath);
    std::filesystem::path canonicalPath = std::filesystem::weakly_canonical(path);
    std::string npath = canonicalPath.make_preferred().string();
    return npath;
}

weakly_canonical does not throw an exception if path does not exist. canonical does.

like image 93
Andy Avatar answered Oct 24 '25 15:10

Andy


Use std::filesystem::lexically_normal(). This performs a lexical operation only, and unlike weakly_canonical it does not query the filesystem for existing path elements, and makes no attempt to resolve symbolic links.

std::string normalizePath(const std::string& messyPath) {
    return messyPath.lexically_normal();
}
like image 33
jstine Avatar answered Oct 24 '25 14:10

jstine



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!