如何使一个Rubystring安全的文件系统?

我有用户input作为文件名。 当然这不是一个好主意,所以我想放弃除[az][AZ][0-9]_-

例如:

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

应该成为

 my_document_is_____very_interesting___thisIs_nice445_doc.pdf 

然后理想

 my_document_is_very_interesting_thisIs_nice445_doc.pdf 

有没有一个很好的,优雅的方式来做到这一点?

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 

我想build议一个不同于旧的解决scheme。 请注意,旧的使用不赞成 returning 。 顺便说一下, Rails特定于Rails的 ,你没有在你的问题中明确地提到Rails(仅作为标签)。 此外,现有解决scheme无法按照您的要求将_doc.pdf编码为_doc.pdf 。 而且,当然,它不会将下划线合并为一个。

这是我的解决scheme:

 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 

您尚未指定有关转换的所有详细信息。 因此,我做了以下假设:

  • 最多只能有一个文件名扩展名,这意味着文件名最多只能有一个句点
  • 追踪期间不标记分机的开始
  • 领导阶段不标志着延期的开始
  • 任何超出AZaz09-的字符序列都应该折叠成一个_ (即下划线本身被认为是不允许的字符,string'$%__°#'将变成'_' – 而不是从部分'$%''__''°#' '___' '°#'

这个复杂的部分是我把文件名分割成主要部分和扩展名的地方。 在正则expression式的帮助下,我正在search最后一个期间,后面跟着一些不同于句点的内容,以便在string中没有符合相同条件的以下期间。 但是,它必须先加上一些字符,以确保它不是string中的第一个字符。

我testing函数的结果:

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

我想这是你要求的。 我希望这是很好,很优雅。

如果你使用Rails,你也可以使用String#parameterize。 这并不是特意为之,但你会得到满意的结果。

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

对于Rails,我发现自己希望保留任何文件扩展名,但是对其余字符使用parameterize

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

实施细节和想法见源: 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