2010-09-06 9 views
13

C'è un modo per aprire un file senza insensibilità in Ruby sotto Linux? Ad esempio, data la stringa foo.txt, posso aprire il file FOO.txt?Aprire un file senza distinzione tra maiuscole e minuscole in Linux sotto

Un modo possibile è la lettura di tutti i nomi di file nella directory e la ricerca manuale dell'elenco per il file richiesto, ma sto cercando un metodo più diretto.

+2

Cosa succede se più file corrispondono? Scegli uno di loro a caso? –

+0

@ Ignacio: Sì, questa è l'unica opzione ragionevole. Ma quel caso è improbabile nella mia situazione. – imgx64

risposta

17

Anche se non si può fare open case insensitive è possibile scrivere la ricerca di directory che avete suggerito in maniera concisa. per esempio.

filename = Dir.glob('foo.txt', File::FNM_CASEFOLD).first 
if filename 
    # use filename here 
else 
    # no matching file 
end 

ricorda che mentre le documentation suggests that FNM_CASEFOLD can't be used with glob questo sembra non essere corretto o non aggiornate.

Alternative

Se siete preoccupati per utilizzando FNM_CASEFOLD poi un paio di alternative sono:

filename = Dir.glob('*').find { |f| f.downcase == 'foo.txt' } 

o scrivere un po 'di metodo per costruire un caso glob insensibile per un determinato nome di file:

def ci_glob(filename) 
    glob = '' 
    filename.each_char do |c| 
    glob += c.downcase != c.upcase ? "[#{c.downcase}#{c.upcase}]" : c 
    end 
    glob 
end 

irb(main):024:0> ci_glob('foo.txt') 
=> "[fF][oO][oO].[tT][xX][tT]" 

e allora si può fare:

filename = Dir.glob(ci_glob('foo.txt')).first 
+1

Per la maggior parte dei metodi 'IO' e' File', Ruby passa semplicemente tutto alla libc. Quindi, immagino che questo potrebbe funzionare o meno in modo casuale, a seconda di come funziona la libc del tuo sistema operativo. –

+0

@ Jörg Grazie. Ho aggiornato la risposta con un paio di altre idee che evitano la necessità di fare affidamento su 'FNM_CASEFOLD'. – mikej

+0

Sul mio sistema, FNM_CASEFOLD è onorato in Ruby 2.0.0 ma ignorato in Ruby 2.2.0. Sicuramente non affidabile. – Lupius

1

È possibile utilizzare Dir.glob con il flag FNM_CASEFOLD per ottenere un elenco di tutti i nomi di file che corrispondono al nome specificato, ad eccezione del caso. È quindi possibile utilizzare semplicemente first sull'array risultante per ottenere qualsiasi risultato o utilizzare min_by per ottenere quello che corrisponde maggiormente al caso dell'originale.

def find_file(f) 
    Dir.glob(f, File::FNM_CASEFOLD).min_by do |f2| 
    f.chars.zip(f2.chars).count {|c1,c2| c1 != c2} 
    end 
end 

system "touch foo.bar" 
system "touch Foo.Bar" 
Dir.glob("FOO.BAR", File::FNM_CASEFOLD) #=> ["foo.bar", "Foo.Bar"] 
find_file("FOO.BAR") #=> ["Foo.Bar"] 
Problemi correlati