# Split a path (inverse of Base.Filesystem.joinpath())

**URL:** <https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980>\
**Category:** New to Julia\
**Created:** [March 26, 2018, 4:04am UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980 "2018-03-26T04:04:19Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![yig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yig/32/3815_2.png) [@yig](https://discourse.julialang.org/u/yig)\
**Post date:** [March 26, 2018, 4:04am UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980/1 "2018-03-26T04:04:19Z")

</div>

Is there a way to split a path `"a/b/c.txt"` into `["a", "B", "c.txt"]`?  
I could call `Base.Filesystem.splitdir()` in a loop until the first element is the empty string, but that seems wasteful. I could call `split( "a/b/c.txt", Base.Filesystem.path_separator )`, but `Base.Filesystem.path_separator` is undocumented.

In practice, I want to check if the first directory in the path is “…”.

---

<div class="post-metadata">

**Author:** ![yig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yig/32/3815_2.png) [@yig](https://discourse.julialang.org/u/yig)\
**Post date:** [March 26, 2018, 5:51am UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980/2 "2018-03-26T05:51:37Z")

</div>

Here is the function I came up with:

````
"""
    splitpath( path::String ) -> Array{String}

Splits a path into an array of its path components. The inverse of `joinpath()`.
Calling `joinpath( splitpath( path )... )` should produce `path`
(possible with the trailing slash removed).

```jldoctest
julia> splitpath("a/b/c")
("a", "b", "c")
julia> splitpath("/a/b/c")
("/", "a", "b", "c")
```
"""
function splitpath( path::String )
    result = String[]
    
    while path != ""
        path, last = splitdir( path )
        
        ## If path consists of only the path separator, which could happen
        ## when referring to the filesystem root, then last will be empty
        ## and path will be unchanged.
        ## If this is the case, swap them so that we push the root path
        ## marker and then the while loop will terminate.
        if last == ""
            path, last = last, path
        end
        
        push!( result, last )
    end
    
    reverse!( result )
    return result
end

````

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [March 26, 2018, 6:58am UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980/3 "2018-03-26T06:58:22Z")

</div>

> [@yig](#):
>
> In practice, I want to check if the first directory in the path is “…”.

I am not sure that `"..."` is a valid path, but in any case, it is possible that you could also use string (or regex) matching.

---

<div class="post-metadata">

**Author:** ![yig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yig/32/3815_2.png) [@yig](https://discourse.julialang.org/u/yig)\
**Post date:** [March 26, 2018, 11:32am UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980/4 "2018-03-26T11:32:21Z")

</div>

[The “…” is what happens when I don’t enclose `".."` in code backticks on Discourse.]

I can’t use string matching or a regular expression because `Base.Filesystem.path_separator` is undocumented.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [March 26, 2018, 12:12pm UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980/5 "2018-03-26T12:12:00Z")

</div>

I don’t see why you would need to use separators, unless validating paths. Wouldn’t

```julia
startswith(path, "..")

```

just work?

---

<div class="post-metadata">

**Author:** ![yig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yig/32/3815_2.png) [@yig](https://discourse.julialang.org/u/yig)\
**Post date:** [March 26, 2018, 1:28pm UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980/6 "2018-03-26T13:28:59Z")

</div>

There could be a file named `..notes`. I don’t want to exclude it.

---

<div class="post-metadata">

**Author:** ![standarddeviant](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/standarddeviant/32/2309_2.png) [@standarddeviant](https://discourse.julialang.org/u/standarddeviant)\
**Post date:** [May 9, 2018, 3:55pm UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980/7 "2018-05-09T15:55:45Z")

</div>

Recently, I’ve been doing some work, where I want the folder name and the file from an absolute path. What I’ve come up with is:

```julia
last_two_parts(p) = joinpath( basename(dirname(p)), basename(p) )

```

That’s not bad, but the following looks cleaner:

```julia
last_two_parts(p) = joinpath( splitpath(p)[end-1 : end] )

```

It’s also much more flexible syntactically. If there is a performant way to make `splitpath`, I think it would be a really useful function.

---

<div class="post-metadata">

**Author:** ![yig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yig/32/3815_2.png) [@yig](https://discourse.julialang.org/u/yig)\
**Post date:** [May 9, 2018, 4:33pm UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980/8 "2018-05-09T16:33:19Z")

</div>

The computationally efficient way to write it is `split( "a/b/c.txt", Base.Filesystem.path_separator )`. However, `Base.Filesystem.path_separator` is not documented. In contrast, Python exposes `os.sep`.

---

<div class="post-metadata">

**Author:** ![yig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yig/32/3815_2.png) [@yig](https://discourse.julialang.org/u/yig)\
**Post date:** [May 9, 2018, 4:33pm UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980/9 "2018-05-09T16:33:47Z")

</div>

In practice, the performance of even the iterative approach is probably not bottlenecking anyone’s code.

---

<div class="post-metadata">

**Author:** ![standarddeviant](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/standarddeviant/32/2309_2.png) [@standarddeviant](https://discourse.julialang.org/u/standarddeviant)\
**Post date:** [May 9, 2018, 5:03pm UTC](https://discourse.julialang.org/t/split-a-path-inverse-of-base-filesystem-joinpath/9980/10 "2018-05-09T17:03:56Z")

</div>

Changing documentation to add a reference feels like an easy fix. I’ll try to submit a PR for this soon.
