如何使一个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
您尚未指定有关转换的所有详细信息。 因此,我做了以下假设:
- 最多只能有一个文件名扩展名,这意味着文件名最多只能有一个句点
- 追踪期间不标记分机的开始
- 领导阶段不标志着延期的开始
- 任何超出
A
–Z
,a
–z
,0
–9
和-
的字符序列都应该折叠成一个_
(即下划线本身被认为是不允许的字符,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