-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Edit by carlossanlop: I marked this issue as up-for-grabs. If you're interested in taking it, please read this comment. This feature is fully implemented already, but the only thing pending to fix is a Unix performance regression before merging.
Rationale
Currently there is no direct way to normalize the path or to remove the relative Segments from any path string. We can use GetFullPath to normalize the path but it will resolve it relative to root directory or working directory which is not always desired.
eg
-
working with relative paths in archives where we may require normalized paths that are "full" paths in said archive, but not on the system
-
Will help in building and working with relative urls.
Proposed Api
namespace System.IO
{
public class Path
{
public static string RemoveRelativeSegments(string path);
public static string RemoveRelativeSegments(ReadOnlySpan<char> path);
public static bool TryRemoveRelativeSegments(ReadOnlySpan<char> path, span<char> buffer, out int charsWritten);
}
}The rootlength is the length of the path which will never be trimmed while removing the relativeSegments.
Behavior
Path.DirectorySeparatorCharandPath.AltDirectorySeparatorCharare considered path "segment" separators (\and/on Windows,/on Unix)- Sequential separators will be collapsed to a single separator
- Any
Path.AltDirectorySeparatorCharcharacters will be changed toPath.DirectorySeparatorChar(only relevant on Windows). - Segments of one period only
.will be removed. - Segments of two periods only
..will be removed along with the parent segment, if any.
Implementation
This api is already implemented as an internal api and is being used by GetFullPath api to remove relative segments in case of device paths.
| internal static bool RemoveRelativeSegments(ReadOnlySpan<char> path, int rootLength, ref ValueStringBuilder sb) |
Usage
// removing the relative segment
Assert.Equal("C:\temp", PathInternal.RemoveRelativeSegments("C:\git\..\temp"));
// removing the relative segment but not eating the root
Assert.Equal("C:\temp", PathInternal.RemoveRelativeSegments("C:\..\..\temp"));
// Input is relative path
Assert.Equal("temp", PathInternal.RemoveRelativeSegments("git\..\temp"));
// Multiple types of relative Segments together
Assert.Equal("temp", PathInternal.RemoveRelativeSegments("git\.\..\temp"));
Assert.Equal("git\temp", PathInternal.RemoveRelativeSegments("git\\\\temp"));
// Normalizing the path
Assert.Equal("git\temp\src\corefx", PathInternal.RemoveRelativeSegments("git\temp/src\corefx"));More Usages can be find here
dotnet/corefx#37225
I have modified the internal tests to api proposal
Some Design Answers
Resolving this https://github.com/dotnet/corefx/issues/4208
Can directly call RemoveRelativeSegments(RelativePath);
Exception Handling
- return empty string if the path is empty or null.
- throw Argument Exception if the bufferLength is less than the required in TryRemoveRelativeSegments api
cc @danmosemsft @JeremyKuhne
related implementation prs dotnet/coreclr#24273 dotnet/corefx#37225