2010-09-06 2 views
13

Есть ли способ открыть файл без учета регистра в Ruby под Linux? Например, с учетом строки foo.txt, могу ли я открыть файл FOO.txt?Открыть файл без учета регистра в Ruby под Linux

Одним из возможных способов было бы чтение всех файлов в каталоге и поиск в нужном файле вручную, но я ищу более прямой метод.

+2

Что делать, если несколько файлов совпадают? Выберите одного из них наугад? –

+0

@ Игнасио: Да, это единственный разумный вариант. Но этот случай маловероятен в моей ситуации. – imgx64

ответ

17

Хотя вы не можете сделать open чувствителен к регистру, вы можете написать поиск каталога вы предложили довольно сжато. например

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

Обратите внимание, что в то время как documentation suggests that FNM_CASEFOLD can't be used with glob это кажется неправильным или устареть.

Альтернативы

Если вы обеспокоены использованием FNM_CASEFOLD то пару альтернатив:

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

или написать небольшой метод, чтобы построить регистрозависимости Glob для данного файла:

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]" 

, а затем вы можете сделать:

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

Для большинства методов 'IO' и' File' Ruby просто передает все содержимое libc. Таким образом, я предполагаю, что это может быть в основном случайным образом работать или нет, в зависимости от того, как работает libc вашей операционной системы. –

+0

@ Jörg Спасибо. Я обновил ответ с помощью нескольких других идей, которые позволяют избежать необходимости полагаться на 'FNM_CASEFOLD'. – mikej

+0

В моей системе FNM_CASEFOLD исполняется в Ruby 2.0.0, но игнорируется в Ruby 2.2.0. Определенно ненадежны. – Lupius

1

Вы можете использовать Dir.glob с флагом FNM_CASEFOLD, чтобы получить список всех имен файлов, соответствующих указанному имени, за исключением случая. Затем вы можете просто использовать first в результирующем массиве, чтобы получить какой-либо результат, или использовать min_by, чтобы получить тот, который наиболее точно соответствует случаю orignial.

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"] 
Смежные вопросы