Как разбить строку каталога в 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']

Вы можете продолжить эту идею, если хотите.