std::filesystem::path::lexically_normal, std::filesystem::path::lexically_relative, std::filesystem::path::lexically_proximate

From cppreference.com
< cpplrm; | filesystemlrm; | path
path lexically_normal() const;
(1) (since C++17)
path lexically_relative(const path& base) const;
(2) (since C++17)
path lexically_proximate(const path& base) const;
(3) (since C++17)
1) Returns *this converted to normal form in its generic format
2) Returns *this made relative to base.
  • First, if root_name() != base.root_name() || is_absolute() != base.is_absolute() || (!has_root_directory() && base.has_root_directory()), returns a default-constructed path.
  • Otherwise, first determines the first mismatched element of *this and base as if by auto [a, b] = mismatch(begin(), end(), base.begin(), base.end()), then
  • if a == end() and b == base.end(), returns path(".");
  • otherwise, if the number of dot-dot filename elements in [b, base.end()) is greater than the number of filename elements that are neither dot nor dot-dot, returns a default-constructed path.
  • otherwise returns an object composed from
  • a default-constructed path() followed by
  • as many applications of operator/=(path("..")) as there were filename elements in [b, base.end()) that are neither dot nor dot-dot minus number of dot-dot elements in that range, followed by
  • one application of operator/= for each element in the half-open range [a, end())
3) If the value of lexically_relative(base) is not an empty path, return it. Otherwise return *this.

Parameters

(none)

Return value

1) The normal form of the path
2) The relative form of the path
3) The proximate form of the path

Exceptions

(none)

Notes

These conversions are purely lexical. They do not check that the paths exist, do not follow symlinks, and do not access the filesystem at all. For symlink-following counterparts of lexically_relative and lexically_proximate, see relative and proximate.

On Windows, the returned path has backslashes (the preferred separators),

Example

#include <iostream>
#include <filesystem>
#include <cassert>
namespace fs = std::filesystem;

int main()
{
    assert(fs::path("foo/./bar/..").lexically_normal() == "foo/");
    assert(fs::path("foo/.///bar/../").lexically_normal() == "foo/");

    assert(fs::path("/a/d").lexically_relative("/a/b/c") == "../../d");
    assert(fs::path("/a/b/c").lexically_relative("/a/d") == "../b/c");
    assert(fs::path("a/b/c").lexically_relative("a") == "b/c");
    assert(fs::path("a/b/c").lexically_relative("a/b/c/x/y") == "../..");
    assert(fs::path("a/b/c").lexically_relative("a/b/c") == ".");
    assert(fs::path("a/b").lexically_relative("c/d") == "../../a/b");
}


See also

composes a relative path
(function)