2009-09-03 20 views
17

En Ruby, yo soy capaz de hacer¿Cómo dividir una cadena de directorio en Ruby?

File.dirname("/home/gumby/bigproject/now_with_bugs_fixed/32/FOO_BAR_2096.results") 

y obtener

"/home/gumby/bigproject/now_with_bugs_fixed/32" 

pero ahora me gustaría dividir esa cadena de directorios en los componentes individuales de la carpeta, es decir, algo así como

["home", "gumby", "bigproject", "now_with_bugs_fixed", "32"] 

¿hay una manera de hacerlo que no sea usando

directory.split("/")[1:-1] 

Respuesta

22

No hay ninguna función integrada para dividir un trazado en sus directorios de componentes como que hay a unirse a ellos, pero se puede tratar de fingir de manera multiplataforma:

directory_string.split(File::SEPARATOR) 

Esto funciona con relativa rutas y en plataformas que no son de Unix, pero para una ruta que comienza con "/" como directorio raíz, obtendrá una cadena vacía como primer elemento de la matriz y, en su lugar, querría "/".

directory_string.split(File::SEPARATOR).map {|x| x=="" ? File::SEPARATOR : x} 

Si desea que sólo los directorios sin el directorio raíz como usted ha mencionado anteriormente, a continuación se puede cambiar para seleccionar entre el primer elemento de.

directory_string.split(File::SEPARATOR).map {|x| x=="" ? File::SEPARATOR : x}[1..-1] 
+5

Tenga en cuenta que el archivo de Windows :: SEPARADOR es /, no \. Entonces, si solo usa ese método en el resultado de File.join, funcionará bien, pero si quiere trabajar con la entrada del usuario u otras fuentes que podrían usar \ como un separador de archivos, debería hacer algo como 'dir.split (Regexp.union (* [File :: SEPARATOR, File :: ALT_SEPARATOR] .compact)) '(o una versión más legible de eso) – sepp2k

+5

Lamento el spam, pero esta solución es indiscutiblemente mejor: http://stackoverflow.com/a/ 21572944/924109 –

7

Rake proporciona un método split_all agregado a FileUtils. Es muy sencillo y utiliza 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 

versión El rastrillo tiene unos resultados ligeramente distinto al código de Rudd. La versión de rastrillo ignora múltiples barras:

 
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> 
2

Advertencia: Esta solución ya no es la mejor. Ver mi otro.

En realidad, hay una solución más ordenada. La idea principal es seguir mostrando el basename hasta que solo quede con . o /.

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'] 

Puede seguir desarrollando esta idea, si lo desea.

33

La respuesta correcta es usar Ruby's Pathname (clase incorporada desde 1.8.7, no una joya).

ver el código:

require 'pathname' 

def split_path(path) 
    Pathname(path).each_filename.to_a 
end 

Hacer esto descartará la información de si el camino era absoluta o relativa. Para detectar esto, puede llamar al método absolute? en Pathname.

Fuente: https://ruby-doc.org/stdlib-2.3.3/libdoc/pathname/rdoc/Pathname.html

+1

Acepto usar Pathname. también podemos escribir con el método Tap de la siguiente manera: '[] .tap {| x | Pathname.new ("/ home/gumby/bigproject/now_with_bugs_fixed/32"). Each_filename {| d | x << d}} ' –

+0

Hola señor, juntos logramos obtener una solución perfecta. Gracias de nuevo. –

+0

Vale la pena señalar que 'File.join (Pathname (path) .each_filename.to_a)! = Path' en caso de ruta absoluta. –

Cuestiones relacionadas