it-swarm.com.de

Wie mache ich einen Ruby-String sicher für ein Dateisystem?

Ich habe Benutzereinträge als Dateinamen. Das ist natürlich keine gute Idee, deshalb möchte ich alles außer [a-z], [A-Z], [0-9], _ und - löschen.

Zum Beispiel:

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

soll werden

my_document_is_____very_interesting___thisIs_Nice445_doc.pdf

und dann im Idealfall

my_document_is_very_interesting_thisIs_Nice445_doc.pdf

Gibt es eine schöne und elegante Möglichkeit, dies zu tun?

39
marcgg

Von 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
26
miku

Ich möchte eine Lösung vorschlagen, die sich von der alten unterscheidet. Beachten Sie, dass der alte den veraltetreturning verwendet. Übrigens ist es sowieso spezifisch für Rails, und Sie haben Rails in Ihrer Frage nicht explizit erwähnt (nur als Tag). Außerdem kann die vorhandene Lösung .doc.pdf nicht wie gewünscht in _doc.pdf kodieren. Und natürlich lassen sich die Unterstriche nicht zu einem zusammenfalten.

Hier ist meine Lösung:

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

Sie haben nicht alle Details zur Konvertierung angegeben. Daher mache ich folgende Annahmen:

  • Es sollte höchstens eine Dateinamenerweiterung geben, das heißt, im Dateinamen darf höchstens ein Punkt enthalten sein
  • Nachlaufzeiten kennzeichnen nicht den Beginn einer Erweiterung
  • Vorlaufzeiten kennzeichnen nicht den Beginn einer Verlängerung
  • Jede Folge von Zeichen über A-Z, a-z, 0-9 und - sollte in einen einzigen _ zusammengelegt werden (dh unterstreicht selbst als nicht erlaubte Zeichen angesehen, und die Zeichenfolge '$%__°#' würde '_' - anstatt '___' aus den Teilen '$%', '__' und '°#')

Der komplizierte Teil davon ist, wo ich den Dateinamen in den Hauptteil und die Erweiterung aufteilte. Mit Hilfe eines regulären Ausdrucks suche ich nach der letzten Periode, auf die etwas anderes als eine Periode folgt, so dass keine Folgeperioden mit denselben Kriterien in der Zeichenfolge übereinstimmen. Es muss jedoch ein Zeichen vorangestellt werden, um sicherzustellen, dass es nicht das erste Zeichen in der Zeichenfolge ist.

Meine Ergebnisse beim Testen der Funktion:

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

was ich denke, ist das, was Sie verlangt haben. Ich hoffe das ist schön und schön genug.

57

Wenn Sie Rails verwenden, können Sie auch String # parametrisieren. Dies ist nicht speziell dafür gedacht, aber Sie werden ein zufriedenstellendes Ergebnis erzielen.

"my§document$is°°   very&interesting___thisIs%Nice445.doc.pdf".parameterize
16
albandiguer

Für Rails wollte ich alle Dateierweiterungen behalten, aber parameterize für den Rest der Zeichen verwenden:

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

Implementierungsdetails und Ideen siehe Quelle: 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
0
Blair Anderson

In Rails können Sie möglicherweise auch sanitize aus ActiveStorage :: Filename : verwenden.

ActiveStorage::Filename.new("foo:bar.jpg").sanitized # => "foo-bar.jpg"
ActiveStorage::Filename.new("foo/bar.jpg").sanitized # => "foo-bar.jpg"
0
morgler

Es gibt eine Bibliothek, die hilfreich sein kann, besonders wenn Sie daran interessiert sind, komische Unicode-Zeichen durch ASCII zu ersetzen: unidecode .

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