rails how awesome application ruby-on-rails ruby string filesystems

ruby on rails - how - ¿Cómo hacer que una cadena de Ruby sea segura para un sistema de archivos?



ruby encoding (5)

Tengo entradas de usuario como nombres de archivo. Por supuesto, esta no es una buena idea, así que quiero dejar todo excepto [az] , [AZ] , [0-9] , _ y - .

Por ejemplo:

my§document$is°° very&interesting___thisIs%nice445.doc.pdf

debe convertirse

my_document_is_____very_interesting___thisIs_nice445_doc.pdf

y luego idealmente

my_document_is_very_interesting_thisIs_nice445_doc.pdf

¿Hay alguna manera agradable y elegante para hacer esto?



Hay una biblioteca que puede ser útil, especialmente si está interesado en reemplazar caracteres Unicode extraños con ASCII: unidecode .

irb(main):001:0> require ''unidecoder'' => true irb(main):004:0> "Grzegżółka".to_ascii => "Grzegzolka"


Me gustaría sugerir una solución que difiera de la anterior. Tenga en cuenta que el anterior usa el returning obsoleto . Por cierto, es de todos modos específico para Rails , y no mencionaste explícitamente a Rails en tu pregunta (solo como una etiqueta). Además, la solución existente no codifica .doc.pdf en _doc.pdf , como solicitó. Y, por supuesto, no colapsa los guiones bajos en uno.

Aquí está mi solución:

def sanitize_filename(filename) # Split the name when finding a period which is preceded by some # character, and is followed by some character other than a period, # if there is no following period that is followed by something # other than a period (yeah, confusing, I know) fn = filename.split /(?<=.)/.(?=[^.])(?!.*/.[^.])/m # We now have one or two parts (depending on whether we could find # a suitable period). For each of these parts, replace any unwanted # sequence of characters with an underscore fn.map! { |s| s.gsub /[^a-z0-9/-]+/i, ''_'' } # Finally, join the parts with a period and return the result return fn.join ''.'' end

No ha especificado todos los detalles sobre la conversión. Por lo tanto, estoy haciendo las siguientes suposiciones:

  • Debe haber como máximo una extensión de nombre de archivo, lo que significa que debe haber como máximo un punto en el nombre de archivo
  • Los períodos finales no marcan el inicio de una extensión
  • Los períodos iniciales no marcan el inicio de una extensión
  • Cualquier secuencia de caracteres más allá de A - Z , a - z , 0 - 9 y - debe colapsarse en un solo _ (es decir, el subrayado se considera un carácter no permitido, y la cadena ''$%__°#'' se convertiría en ''_'' - en lugar de ''___'' de las partes ''$%'' , ''__'' y ''°#'' )

La parte complicada de esto es donde dividí el nombre de archivo en la parte principal y la extensión. Con la ayuda de una expresión regular, estoy buscando el último período, que es seguido por algo más que un punto, de modo que no haya períodos siguientes que coincidan con los mismos criterios en la cadena. Sin embargo, debe ir precedido de algún carácter para asegurarse de que no sea el primer personaje de la cadena.

Mis resultados al probar la función:

1.9.3p125 :006 > sanitize_filename ''my§document$is°° very&interesting___thisIs%nice445.doc.pdf'' => "my_document_is_very_interesting_thisIs_nice445_doc.pdf"

que creo que es lo que solicitaste Espero que esto sea lo suficientemente lindo y elegante.


Para Rails, me encontré que quería guardar cualquier extensión de archivo pero usando parameterize para el resto de los caracteres:

filename = "my§doc$is°° very&itng___thsIs%nie445.doc.pdf" cleaned = filename.split(".").map(&:parameterize).join(".")

Detalles de implementación e ideas ver fuente: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/transliterate.rb

def parameterize(string, separator: "-", preserve_case: false) # Turn unwanted chars into the separator. parameterized_string.gsub!(/[^a-z0-9/-_]+/i, separator) #... some more stuff end


Si usa Rails, también puede usar String # parameterize. Esto no es especialmente adecuado para eso, pero obtendrá un resultado satisfactorio.

"my§document$is°° very&interesting___thisIs%nice445.doc.pdf".parameterize