Как разбить строку каталога в Ruby?
В рубине я могу сделать
File.dirname("/home/gumby/bigproject/now_with_bugs_fixed/32/FOO_BAR_2096.results")
и получим
"/home/gumby/bigproject/now_with_bugs_fixed/32"
но теперь я хотел бы разделить эту строку каталога на отдельные компоненты папки, то есть что-то вроде
["home", "gumby", "bigproject", "now_with_bugs_fixed", "32"]
Есть ли способ сделать это, кроме использования
directory.split("/")[1:-1]
Ответы
Ответ 1
Нет встроенной функции для разделения пути на свои каталоги компонентов, например, чтобы присоединиться к ним, но вы можете попытаться подделать его кросс-платформенным способом:
directory_string.split(File::SEPARATOR)
Это работает с относительными путями и на платформах, отличных от Unix, но для пути, начинающегося с "/"
в качестве корневого каталога, вы получите пустую строку в качестве своего первого элемента в массиве, и мы Вместо этого нужно "/"
.
directory_string.split(File::SEPARATOR).map {|x| x=="" ? File::SEPARATOR : x}
Если вам нужны только каталоги без корневого каталога, как вы упомянули выше, вы можете изменить его, чтобы выбрать из первого элемента.
directory_string.split(File::SEPARATOR).map {|x| x=="" ? File::SEPARATOR : x}[1..-1]
Ответ 2
Правильный ответ - использовать Ruby Pathname
(встроенный класс с 1.8.7, а не самоцвет).
Смотрите код:
require 'pathname'
def split_path(path)
Pathname(path).each_filename.to_a
end
Выполнение этого приведет к отбрасыванию информации о том, был ли путь абсолютным или относительным. Чтобы обнаружить это, вы можете вызвать метод absolute?
на Pathname
.
Источник: https://ruby-doc.org/stdlib-2.3.3/libdoc/pathname/rdoc/Pathname.html
Ответ 3
Rake предоставляет метод split_all, добавленный в FileUtils. Это довольно просто и использует File.split:
def split_all(path)
head, tail = File.split(path)
return [tail] if head == '.' || tail == '/'
return [head, tail] if head == '/'
return split_all(head) + [tail]
end
taken from rake-0.9.2/lib/rake/file_utils.rb
У версии rake есть немного отличный результат от кода Rudd. В версии Rake игнорируется несколько слэшей:
irb(main):014:0> directory_string = "/foo/bar///../fn"
=> "/foo/bar///../fn"
irb(main):015:0> directory_string.split(File::SEPARATOR).map {|x| x=="" ? File::SEPARATOR : x}[1..-1]
=> ["foo", "bar", "/", "/", "..", "fn"]
irb(main):016:0> split_all directory_string
=> ["/", "foo", "bar", "..", "fn"]
irb(main):017:0>
Ответ 4
Предупреждение. Это решение уже не самое лучшее. См. Мой другой.
Собственно, есть более аккуратное решение. Основная идея заключается в том, чтобы вызывать базовое имя, пока вы не останетесь с .
или /
.
def split_path(path)
array = []
until ['/', '.'].include? path
array << File.basename(path)
path = File.dirname(path)
end
array.reverse
end
split_path 'a/b/c/d' #=> ['a', 'b', 'c', 'd']
Вы можете продолжить эту идею, если хотите.