2010-12-27 12 views
1

Ich habe eine Methode in einem Ruby-Skript, das versucht, Dateien vor dem Speichern umzubenennen. Es sieht wie folgt aus:Teil eines Strings in Ruby erhöhen

def increment (path) 
    if path[-3,2] == "_#" 
     print " Incremented file with that name already exists, renaming\n" 
     count = path[-1].chr.to_i + 1 
     return path.chop! << count.to_s 
    else 
     print " A file with that name already exists, renaming\n" 
     return path << "_#1" 
    end 
end 

Angenommen, Sie haben drei Dateien mit dem gleichen Namen in einem Verzeichnis gespeichert werden, werden sagen, dass wir die Datei example.mp3 genannt wird. Die Idee ist, dass die erste als example.mp3 gespeichert wird (da es nicht von if File.exists?("#{file_path}.mp3") an anderer Stelle im Skript abgefangen wird), die zweite wird als example_#1.mp3 gespeichert (da es von der else Teil der oben genannten Methode gefangen wird) und der 3. als example_#2.mp3 (da es durch den if Teil der oben genannten Methode gefangen ist).

Das Problem, das ich habe, ist zweifach.

1) if path[-3,2] == "_#" nicht mit einer ganzen Zahl von mehr als eine Ziffer (example_#11.mp3 beispielsweise für Dateien arbeiten), da die Zeichenplatzierung falsch sein (Sie es brauchen würden path[-4,2] zu sein, aber dann, die nicht mit nicht zu bewältigen 3-stellige Nummern usw.).

2) Ich erreiche nie das Problem 1), da die Methode Dateinamen nicht zuverlässig abfängt. Im Moment wird das erste in example_#1.mp3 umbenannt, aber das zweite wird in dasselbe umbenannt (wodurch die zuvor gespeicherte Datei überschrieben wird).

Dies ist möglicherweise zu vage für Stack Overflow, aber ich kann nichts finden, das das Problem der Erhöhung eines bestimmten Teils einer Zeichenfolge behandelt.

Vielen Dank im Voraus!

Bearbeiten/Update:

unter Wayne Methode auf seine eigenen zu funktionieren scheint, aber nicht, wenn sie als Teil des gesamten Skript enthält - es einmal eine Datei erhöhen kann (example.mp3-example_#1.mp3) aber nicht bewältigen mit example_#1.mp3 und erhöhen es auf example_#2.mp3. Um ein wenig mehr Kontext zu machen - zur Zeit, wenn das Skript eine Datei zu speichern, findet es den Namen Wayne Methode wie folgt übergeben:

file_name = increment(image_name) 
File.open("images/#{file_name}.jpeg", 'w') do |output| 
    open(image_url) do |input| 
     output << input.read 
    end 
end  

Ich habe Wayne Skript bearbeitet ein wenig so jetzt sieht es wie folgt aus:

def increment (name) 
    name = name.gsub(/\s{2,}|(http:\/\/)|(www.)/i, '') 
    if File.exists?("images/#{name}.jpeg") 
     _, filename, count, extension = *name.match(/(\A.*?)(?:_#(\d+))?(\.[^.]*)?\Z/) 
     count = (count || '0').to_i + 1 
     "#{name}_##{count}#{extension}" 
    else 
     return name 
    end 
end 

Wohin gehe ich falsch? Nochmals vielen Dank im Voraus.

+0

Wir brauchen den Inhalt datei_name kennen zu wissen mit Sicherheit, was schief gelaufen ist, aber sowohl meine Funktion als auch @ Phrog enthalten die Erweiterung (zB '.jpeg') im inkrementierten Dateinamen. Versuchen Sie, '" images/# {file_name} .jpeg "' in '" images/# {file_name} "' zu ändern. Wenn Dateiname auch einen Pfad enthält, können Sie auch 'images /' entfernen, so dass Sie 'File.open (Dateiname, ...)' ' –

+0

' file_name' haben keinen Pfad oder eine Erweiterung. Ich denke, ich habe das Problem jedoch erkannt: Wenn increment läuft 'if File.exists? (" Images/# {name} .jpeg ")' es wird nur nach einer nicht inkrementierten Datei gesucht (zB 'example.jpeg'). Wenn mehr als 2 Dateien mit dem gleichen 'file_name' auftauchen, werden alle nach dem 2. in' example_ # 1.jpeg' geschrieben. Ist das sinnvoll? – Rik

+0

Ich denke, Dateiname muss den Pfad und die Erweiterung von Anfang an enthalten. Das sollte es beheben. Außer dem Variablennamen, der wahrscheinlich 'Pfad' anstelle von' Dateiname' sein sollte, damit der Code die Wahrheit sagt. –

Antwort

7

Ein regulärer Ausdruck wird git ‚er getan:

#!/usr/bin/ruby1.8 

def increment(path) 
    _, filename, count, extension = *path.match(/(\A.*?)(?:_#(\d+))?(\.[^.]*)?\Z/) 
    count = (count || '0').to_i + 1 
    "#{filename}_##{count}#{extension}" 
end 

p increment('example')  # => "example_#1" 
p increment('example.')  # => "example_#1." 
p increment('example.mp3') # => "example_#1.mp3" 
p increment('example_#1.mp3') # => "example_#2.mp3" 
p increment('example_#2.mp3') # => "example_#3.mp3" 

Dies ist wahrscheinlich keine Rolle spielt für den Code, den Sie schreiben, aber wenn Sie jemals mehrere Threads oder Prozesse mit diesen Algorithmus auf derselben haben Dateien, gibt es eine Race-Bedingung beim Überprüfen der Existenz vor dem Speichern: Zwei Autoren können beide den gleichen Dateinamen unbenutzt finden und schreiben. Wenn das für Sie wichtig ist, öffnen Sie die Datei in einem Modus, der fehlschlägt, falls vorhanden, um die Ausnahme zu retten. Wenn die Ausnahme auftritt, wählen Sie einen anderen Namen.Grob:

loop do 
    begin 
    File.open(filename, File::CREAT | File::EXCL | File::WRONLY) do |file| 
     file.puts "Your content goes here" 
    end 
    break 
    rescue Errno::EEXIST 
    filename = increment(filename) 
    redo 
    end 
end 
+0

+1 für Splatting das Spiel :) – Phrogz

+0

Dies scheint zu funktionieren, wenn es selbst ausgeführt wird, aber nicht, wenn es als Teil des gesamten Skripts enthalten ist. Ich habe meinen ursprünglichen Beitrag oben zur Erläuterung erweitert. Auch, darüber hinaus mit dem Threading Beispiel :) Danke! – Rik

2

Hier ist eine Variante, die einen Dateinamen nicht mit einer vorhandenen Zählung akzeptiert:

def non_colliding_filename(filename) 
    if File.exists?(filename) 
    base,ext = /\A(.+?)(\.[^.]+)?\Z/.match(filename).to_a[1..-1] 
    i = 1 
    i += 1 while File.exists?(filename="#{base}_##{i}#{ext}") 
    end 
    filename 
end 

Beweis:

%w[ foo bar.mp3 jim.bob.mp3 ].each do |desired| 
    3.times{ 
    file = non_colliding_filename(desired) 
    p file 
    File.open(file, 'w'){ |f| f << "tmp" } 
    } 
end 
#=> "foo" 
#=> "foo_#1" 
#=> "foo_#2" 
#=> "bar.mp3" 
#=> "bar_#1.mp3" 
#=> "bar_#2.mp3" 
#=> "jim.bob.mp3" 
#=> "jim.bob_#1.mp3" 
#=> "jim.bob_#2.mp3" 
Verwandte Themen