Last active
November 22, 2022 14:38
-
-
Save JoshCheek/e269335f63b154d2eac37a8251230d6b to your computer and use it in GitHub Desktop.
Split slashes in paths, but not URLs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def split_path(path) | |
slash = Regexp.escape File::SEPARATOR | |
match = path.match(%r~ # regex that is delimited by tildes so I can use slashes, quotes, backticks, etc in the comments | |
( # capture whatever the path_slash group matches | |
(?<path_slash> # a named group that matches slashes in paths, but not urls, eg will not match "http://example.com" | |
# don't match first slash in "://" | |
(?: # don't capture this group | |
(?<!:) # not preceeded by ":" | |
(?!#{slash}#{slash}) # not succeeded by "//" (we haven't matched the slash yet, so it's in front of the cursor) | |
) | |
# don't match second slash in "://" | |
(?<!:#{slash}) # not preceeded by ":/" | |
# match any number of slashes eg `File.split "a//b" # => ["a", "b"]` | |
(?:#{slash})+ # but don't capture them | |
) | |
) | |
(?= # make sure it's the last path slash (no more after it) | |
(?: # don't capture this group | |
(?!\g<path_slash>) # there is not a path slash in after the cursor | |
. # consume the next character | |
)* # 0 or more of these (eg can be the last thing in the string) | |
\z # and then the string ends | |
) | |
~xo) # x ignores whitespace and comments, o means it will onlly build the regex the first time it's evaluated | |
if !match | |
[".", path] # File.split "" # => [".", ""] | |
elsif match.pre_match.empty? && match.post_match.empty? | |
[slash, slash] # File.split "/" # => ["/", "/"] | |
elsif match.pre_match.empty? | |
[slash, match.post_match] # File.split "/a" # => ["/", "a"] | |
elsif match.post_match.empty? | |
split_path(match.pre_match) # File.split "a/b/" # => ["a", "b"] | |
else | |
[match.pre_match, match.post_match] # File.split "a/b" # => ["a", "b"] | |
end | |
end | |
def components_of(path) | |
dirname, basename = split_path path | |
return [basename] if basename == path | |
components_of(dirname) << basename | |
end | |
components_of "/a/b/c.rb" | |
# => ["/", "a", "b", "c.rb"] | |
components_of "./a/b//c.rb" | |
# => [".", "a", "b", "c.rb"] | |
components_of "http://example.com/some/path" | |
# => ["http://example.com", "some", "path"] | |
components_of "path/to////test/namespace_with_the_url_http://url1.com_in_it/test_with_url_http://url2.com_in_it" | |
# => ["path", | |
# "to", | |
# "test", | |
# "namespace_with_the_url_http://url1.com_in_it", | |
# "test_with_url_http://url2.com_in_it"] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment