A Appendix

The algorithm in RFC 3986 Section "5.2.4. Remove Dot Segments" is modified to keep leading "../" segments and to prevent the erroneous creation of an output that looks like a net path.  Deletions are indicated like this and additions are indicated like this.
  1. The input buffer is initialized with the now-appended path components and the output buffer is initialized to the empty string.  then replace occurrences of "//" in the input buffer with "/" until no more occurrences of "//" are in the input buffer. If the input buffer starts with a root slash "/" the output buffer is initialized with this root slash "/" otherwise with the empty string.
  2. While the input buffer is not empty, loop as follows:
    1. If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer , else if the input buffer begins with a prefix of "../", then if also the output does not contain the root slash "/" only, then move this prefix to the end of the output buffer else remove that prefix ; otherwise,
    2. if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
    3. if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and if also the output buffer is empty, last segment in the output buffer equals "../" or "..", where ".." is a complete path segment, then append ".." or "/.." for the latter case respectively to the output buffer else remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
    4. if the input buffer consists only of "." or "..", then remove that from the input buffer else if the input buffer consists only of ".."and and if the output buffer does not contain only the root slash "/", then move the ".." to the output buffer else delte it.; otherwise,
    5. move the first path segment (if any) in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer.
  3. Finally, if the only or last segment of the output buffer is "..", where ".." is a complete path segment not followed by a slash then append a slash "/". Thethe output buffer is returned as the result of remove_dot_segments

Some Examples:

Input Output
no/.././/pseudo-netpath/seg/file.extpseudo-netpath/seg/file.ext
no/..//.///pseudo-netpath/seg/file.extpseudo-netpath/seg/file.ext
yes/no//..//.///pseudo-netpath/seg/file.extyes/pseudo-netpath/seg/file.ext
no/../yesyes
no/../yes/yes/
no/../yes/no/..yes/
../../no/../..../../../
no/../..../
no/.. 
no/../ 
/a/b/c/./../../g/a/g
mid/content=5/../6mid/6
../../..../../../
no/../../../
..yes/..no/..no/..no/../../../..yes..yes/..yes
..yes/..no/..no/..no/../../../..yes/..yes/..yes/
../..../../
../../../../../../
. 
./ 
./. 
//no/../
../../no/..../../
../../no/../../../
yes/no/../yes/
yes/no/no/../..yes/
yes/no/no/no/../../..yes/
yes/no/../yes/no/no/../..yes/yes/
yes/no/no/no/../../../yesyes/yes
yes/no/no/no/../../../yes/yes/yes/
/no/..//
/yes/no/..//yes/
/yes/no/no/../../yes/
/yes/no/no/no/../../../yes/
../../..no/..../../
../../..no/../../../
..yes/..no/../..yes/
..yes/..no/..no/../....yes/
..yes/...no/..no/..no/../../....yes/
..yes/..no/../..yes/..no/..no/../....yes/..yes/
/..no/..//
/..yes/..no/..//..yes/
/..yes/..no/..no/../../..yes/
/..yes/..no/..no/..no/../../../..yes/
//
/./
/.//
/././
/././/
/../
/../../
/../../../
/../../../
//../
//..//../
//..//..//../
/./../
/./.././../
/./.././.././../
. 
./ 
./. 
..../
../../