ファイル名としてユーザーエントリがあります。もちろん、これは良い考えではないので、[a-z]
、[A-Z]
、[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
古いソリューションとは異なるソリューションを提案したいと思います。古いものは非推奨returning
を使用していることに注意してください。ちなみに、それはとにかくRailsに固有であり、質問で(タグとしてのみ)Rails)を明示的に言及していませんでした。また、既存のソリューションは失敗します.doc.pdf
を_doc.pdf
にエンコードします(もちろん、アンダースコアは1つに縮小されません)。
これが私の解決策です:
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
および-
を超える文字のシーケンス単一の_
に折りたたむ必要があります(つまり、アンダースコア自体は許可されていない文字と見なされ、文字列'$%__°#'
は'_'
からではなく'___'
になります'$%'
、'__'
、'°#'
)この複雑な部分は、ファイル名をメイン部分と拡張子に分割するところです。正規表現を使用して、最後のピリオドを検索します。最後のピリオドの後にピリオド以外の何かが続きます。これにより、文字列内で同じ基準に一致する後続のピリオドがなくなります。ただし、文字列の最初の文字ではないことを確認するために、文字の前に置く必要があります。
関数をテストした結果:
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では、_ ActiveStorage :: Filename からsanitize
を使用できる場合もあります:
ActiveStorage::Filename.new("foo:bar.jpg").sanitized # => "foo-bar.jpg"
ActiveStorage::Filename.new("foo/bar.jpg").sanitized # => "foo-bar.jpg"
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
特に奇妙なUnicode文字をASCIIに置き換えることに興味がある場合は、役立つライブラリがあります: nidecode 。
irb(main):001:0> require 'unidecoder'
=> true
irb(main):004:0> "Grzegżółka".to_ascii
=> "Grzegzolka"
あなたの目標がすべてのオペレーティングシステムで使用するのに「安全」なファイル名を生成することだけである(そしてすべての非ASCII文字を削除しない)場合は、 zar gemをお勧めします。元の質問で指定されたすべてのことを行うわけではありませんが、生成されたファイル名は安全に使用できます(ファイル名に安全なUnicode文字はそのままにしておきます)。
Zaru.sanitize! " what\ēver//wëird:user:înput:"
# => "whatēverwëirduserînput"
Zaru.sanitize! "my§docu*ment$is°° very&interes:ting___thisIs%Nice445.doc.pdf"
# => "my§document$is°° very&interesting___thisIs%Nice445.doc.pdf"