简体   繁体   中英

Extract normalized/canonical directory name from path via Ruby stdlib?

Say you have a path String that can be one of:

  • Foo/Bar/Baz.txt
  • Foo/Bar/
  • Foo/Bar

And in each case, you wish to isolate the directory hierarchy within the String, using methods in the Ruby standard library, resulting in the value Foo/Bar . Is there a single method that does this? Unfortunately, Path#cleanpath and other methods in the API preserve the trailing slash in the String.

Is there a single method or short method chain that behaves like the following?

File.directory?(path) ? path.chomp("/") : File.split(path)[0]

Another example of the desired behavior via a regex, is here in this question .

No, there does not seem to be a way to do this explicitly in the Ruby API. The alternative is to use a regex, similar to what you see here .

Not quite sure if I understood your question, but if you want to split the directory and the file you could do like this:

path = "/etc/hosts" ; File.directory?(path) &&  [ File.dirname(path) + "/" +  
File.basename(path), nil ]  ||  [ File.dirname(path),  File.basename(path) ]
=> ["/etc", "hosts"]

path = "/var/lib" ; File.directory?(path) &&  [ File.dirname(path) + "/" +  
File.basename(path), nil ]  ||  [ File.dirname(path),  File.basename(path) ]
=> ["/var/lib", nil]

But note that this solutions applies only to the domain of existing files. If you are planning to create a path, it is impossible to know where Bar should be placed in the answer (in the above example, it will be considered a file).

Note that the answer is supposed to be normalized:

path = "//etc//hosts" ; File.directory?(path) &&  [ File.dirname(path) + "/" +  
File.basename(path), nil ]  ||  [ File.dirname(path),  File.basename(path) ]
=> ["/etc", "hosts"]

However the normalization of dirname is limited/buggy (in my opinion):

path = "/./etc//hosts" ; File.directory?(path) &&  [ File.dirname(path) + "/" 
+  File.basename(path), nil ]  ||  [ File.dirname(path),  File.basename(path) ]
=> ["/./etc", "hosts"]

Parsing is difficult and whenever possible to avoid it, you will certainly save time. Instead of normalizing file paths, I would rather trust their inode number (again, valid only for the domain of existing files):

[ File.stat("/etc/hosts").ino , File.stat("/./etc/hosts").ino ]
=> [1309513, 1309513]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM