Difference between revisions of "cpp/filesystem/path/lexically normal"
From cppreference.com
< cpp | filesystem | path
Andreas Krug (Talk | contribs) m (fmt, {{c}}, {{range}}, headers sorted) |
|||
(4 intermediate revisions by 4 users not shown) | |||
Line 2: | Line 2: | ||
{{cpp/filesystem/path/navbar}} | {{cpp/filesystem/path/navbar}} | ||
{{dcl begin}} | {{dcl begin}} | ||
− | {{dcl | since=c++17 | num=1 | 1= | + | {{dcl|since=c++17|num=1|1= |
path lexically_normal() const; | path lexically_normal() const; | ||
}} | }} | ||
− | {{dcl | since=c++17 | num=2 | 1= | + | {{dcl|since=c++17|num=2|1= |
− | path lexically_relative(const path& base) const; | + | path lexically_relative( const path& base ) const; |
}} | }} | ||
− | {{dcl | since=c++17 | num=3 | 1= | + | {{dcl|since=c++17|num=3|1= |
− | path lexically_proximate(const path& base) const; | + | path lexically_proximate( const path& base ) const; |
}} | }} | ||
{{dcl end}} | {{dcl end}} | ||
− | @1@ Returns {{ | + | @1@ Returns {{c|*this}} converted to [[cpp/filesystem/path|normal form]] in its generic format. |
− | @2@ Returns {{ | + | @2@ Returns {{c|*this}} made relative to {{c|base}}. |
:* First, if {{c|1=root_name() != base.root_name()}} is {{c|true}} or {{c|1=is_absolute() != base.is_absolute()}} is {{c|true}} or {{c|(!has_root_directory() && base.has_root_directory())}} is {{c|true}} or any filename in {{c|relative_path()}} or {{c|base.relative_path()}} can be interpreted as a {{spar|root-name}}, returns a default-constructed path. | :* First, if {{c|1=root_name() != base.root_name()}} is {{c|true}} or {{c|1=is_absolute() != base.is_absolute()}} is {{c|true}} or {{c|(!has_root_directory() && base.has_root_directory())}} is {{c|true}} or any filename in {{c|relative_path()}} or {{c|base.relative_path()}} can be interpreted as a {{spar|root-name}}, returns a default-constructed path. | ||
− | :* Otherwise, first determines the first mismatched element of {{ | + | :* Otherwise, first determines the first mismatched element of {{c|*this}} and {{c|base}} as if by {{c|auto [a, b] {{=}} mismatch(begin(), end(), base.begin(), base.end())}}, then |
− | ::* if {{c|a {{==}} end()}} and {{c|b {{==}} base.end()}}, returns {{c|path(".")}} | + | ::* if {{c|a {{==}} end()}} and {{c|b {{==}} base.end()}}, returns {{c|path(".")}}, |
− | ::* otherwise, define {{math|N}} as the number of nonempty filename elements that are neither {{spar|dot}} nor {{spar|dot-dot}} in {{c|[b, base.end())}}, minus the number of {{spar|dot-dot}} filename elements, If {{math|N < 0}}, returns a default-constructed path | + | ::* otherwise, define {{math|N}} as the number of nonempty filename elements that are neither {{spar|dot}} nor {{spar|dot-dot}} in {{c|[b, base.end())}}, minus the number of {{spar|dot-dot}} filename elements, If {{math|N < 0}}, returns a default-constructed path, |
− | ::* otherwise, if {{math|N {{=}} 0}} and {{c|a {{==}} end() {{!!}} a->empty()}}, returns {{c|path(".")}} | + | ::* otherwise, if {{math|N {{=}} 0}} and {{c|a {{==}} end() {{!!}} a->empty()}}, returns {{c|path(".")}}, |
::* otherwise returns an object composed from | ::* otherwise returns an object composed from | ||
:::* a default-constructed {{c|path()}} followed by | :::* a default-constructed {{c|path()}} followed by | ||
:::* {{math|N}} applications of {{c|operator/{{=}}(path(".."))}}, followed by | :::* {{math|N}} applications of {{c|operator/{{=}}(path(".."))}}, followed by | ||
− | :::* one application of {{c|1=operator/=}} for each element in the half-open range {{ | + | :::* one application of {{c|1=operator/=}} for each element in the half-open range {{range|a|end()}}. |
− | @3@ If the value of {{c|lexically_relative(base)}} is not an empty path, return it. Otherwise return {{ | + | @3@ If the value of {{c|lexically_relative(base)}} is not an empty path, return it. Otherwise return {{c|*this}}. |
===Parameters=== | ===Parameters=== | ||
Line 30: | Line 30: | ||
===Return value=== | ===Return value=== | ||
− | @1@ The normal form of the path | + | @1@ The normal form of the path. |
− | @2@ The relative form of the path | + | @2@ The relative form of the path. |
− | @3@ The proximate form of the path | + | @3@ The proximate form of the path. |
− | + | {{cpp/impldef exception}} | |
− | + | ||
===Notes=== | ===Notes=== | ||
Line 45: | Line 44: | ||
===Example=== | ===Example=== | ||
− | {{example|code= | + | {{example |
+ | |code= | ||
+ | #include <cassert> | ||
+ | #include <filesystem> | ||
#include <iostream> | #include <iostream> | ||
− | |||
− | |||
namespace fs = std::filesystem; | namespace fs = std::filesystem; | ||
int main() | int main() | ||
{ | { | ||
− | assert(fs::path(" | + | assert(fs::path("a/./b/..").lexically_normal() == "a/"); |
− | assert(fs::path(" | + | assert(fs::path("a/.///b/../").lexically_normal() == "a/"); |
− | + | ||
assert(fs::path("/a/d").lexically_relative("/a/b/c") == "../../d"); | 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/d") == "../b/c"); | ||
Line 62: | Line 61: | ||
assert(fs::path("a/b/c").lexically_relative("a/b/c") == "."); | assert(fs::path("a/b/c").lexically_relative("a/b/c") == "."); | ||
assert(fs::path("a/b").lexically_relative("c/d") == "../../a/b"); | assert(fs::path("a/b").lexically_relative("c/d") == "../../a/b"); | ||
+ | assert(fs::path("a/b").lexically_relative("/a/b") == ""); | ||
+ | assert(fs::path("a/b").lexically_proximate("/a/b") == "a/b"); | ||
} | } | ||
}} | }} | ||
− | === Defect reports === | + | ===Defect reports=== |
{{dr list begin}} | {{dr list begin}} | ||
{{dr list item|wg=lwg|dr=3070|std=c++17|before=a filename that can also be a root-name may cause surprising result|after=treated as error case}} | {{dr list item|wg=lwg|dr=3070|std=c++17|before=a filename that can also be a root-name may cause surprising result|after=treated as error case}} | ||
Line 73: | Line 74: | ||
===See also=== | ===See also=== | ||
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc inc | cpp/filesystem/dsc relative}} | + | {{dsc inc|cpp/filesystem/dsc relative}} |
{{dsc end}} | {{dsc end}} | ||
− | {{langlinks|ja|zh}} | + | {{langlinks|de|es|ja|ru|zh}} |
Latest revision as of 22:24, 5 September 2023
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) |
2) Returns *this made relative to base.
- First, if root_name() != base.root_name() is true or is_absolute() != base.is_absolute() is true or (!has_root_directory() && base.has_root_directory()) is true or any filename in relative_path() or base.relative_path() can be interpreted as a root-name, 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, define N as the number of nonempty filename elements that are neither dot nor dot-dot in [b, base.end()), minus the number of dot-dot filename elements, If N < 0, returns a default-constructed path,
- otherwise, if N = 0 and a == end() || a->empty(), returns path("."),
- otherwise returns an object composed from
- a default-constructed path() followed by
- N applications of operator/=(path("..")), 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.
Contents |
[edit] Parameters
(none)
[edit] Return value
1) The normal form of the path.
2) The relative form of the path.
3) The proximate form of the path.
[edit] Exceptions
May throw implementation-defined exceptions.
[edit] 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).
On POSIX, no filename in a relative path is acceptable as a root-name.
[edit] Example
Run this code
#include <cassert> #include <filesystem> #include <iostream> namespace fs = std::filesystem; int main() { assert(fs::path("a/./b/..").lexically_normal() == "a/"); assert(fs::path("a/.///b/../").lexically_normal() == "a/"); 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"); assert(fs::path("a/b").lexically_relative("/a/b") == ""); assert(fs::path("a/b").lexically_proximate("/a/b") == "a/b"); }
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
LWG 3070 | C++17 | a filename that can also be a root-name may cause surprising result | treated as error case |
LWG 3096 | C++17 | trailing "/" and "/." are handled incorrectly | corrected |
[edit] See also
(C++17) |
composes a relative path (function) |