J'ai des entrées d'utilisateur en tant que noms de fichiers. Bien sûr, ce n’est pas une bonne idée, je souhaite donc tout supprimer, à l'exception de [a-z]
, [A-Z]
, [0-9]
, _
et -
.
Par exemple:
my§document$is°° very&interesting___thisIs%Nice445.doc.pdf
devraient devenir
my_document_is_____very_interesting___thisIs_Nice445_doc.pdf
et idéalement
my_document_is_very_interesting_thisIs_Nice445_doc.pdf
Existe-t-il un moyen agréable et élégant de procéder?
De http://devblog.muziboo.com/2008/06/17/attachment-fu-sanitize-filename-regex-and-unicode-gotcha/ :
def sanitize_filename(filename)
returning filename.strip do |name|
# NOTE: File.basename doesn't work right with Windows paths on Unix
# get only the filename, not the whole path
name.gsub!(/^.*(\\|\/)/, '')
# Strip out the non-ascii character
name.gsub!(/[^0-9A-Za-z.\-]/, '_')
end
end
J'aimerais suggérer une solution différente de l'ancienne. Notez que l'ancien utilise le deprecated returning
. En passant, il s'agit de toute façon spécifique à Rails , et vous n'avez pas explicitement mentionné Rails dans votre question (uniquement en tant que balise). En outre, la solution existante ne parvient pas à coder .doc.pdf
dans _doc.pdf
, comme vous l'avez demandé. Et, bien sûr, cela ne réduit pas les traits de soulignement en un seul.
Voici ma solution:
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
Vous n'avez pas spécifié tous les détails de la conversion. Ainsi, je fais les hypothèses suivantes:
A
– Z
, a
– z
, 0
– 9
et -
doit être réduite en un seul _
(le trait de soulignement est lui-même considéré comme non autorisé, et la chaîne '$%__°#'
deviendrait '_'
- plutôt que '___'
des parties '$%'
, '__'
et '°#'
)La partie compliquée de ceci est où je divise le nom de fichier en partie principale et extension. À l'aide d'une expression régulière, je cherche la dernière période, suivie de quelque chose d'autre qu'une période, de sorte qu'il n'y ait pas de périodes suivantes correspondant aux mêmes critères dans la chaîne. Il doit cependant être précédé d'un caractère pour s'assurer que ce n'est pas le premier caractère de la chaîne.
Mes résultats après avoir testé la fonction:
1.9.3p125 :006 > sanitize_filename 'my§document$is°° very&interesting___thisIs%Nice445.doc.pdf'
=> "my_document_is_very_interesting_thisIs_Nice445_doc.pdf"
ce que je pense est ce que vous avez demandé. J'espère que c'est gentil et assez élégant.
Si vous utilisez Rails, vous pouvez également utiliser String # parameterize. Ce n’est pas spécialement destiné à cela, mais vous obtiendrez un résultat satisfaisant.
"my§document$is°° very&interesting___thisIs%Nice445.doc.pdf".parameterize
Pour Rails, je souhaitais conserver les extensions de fichier, mais en utilisant parameterize
pour le reste des caractères:
filename = "my§doc$is°° very&itng___thsIs%nie445.doc.pdf"
cleaned = filename.split(".").map(&:parameterize).join(".")
Détails et idées de mise en œuvre voir source: 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
Dans Rails, vous pourrez également utiliser sanitize
à partir de ActiveStorage :: Nom du fichier :
ActiveStorage::Filename.new("foo:bar.jpg").sanitized # => "foo-bar.jpg"
ActiveStorage::Filename.new("foo/bar.jpg").sanitized # => "foo-bar.jpg"
Une bibliothèque peut être utile, en particulier si vous souhaitez remplacer des caractères Unicode étranges par ASCII: unidecode .
irb(main):001:0> require 'unidecoder'
=> true
irb(main):004:0> "Grzegżółka".to_ascii
=> "Grzegzolka"