Как мне получить имена всех файлов в одной папке с помощью Ruby?

#ruby #regex

#ruby #регулярное выражение

Вопрос:

Они находятся в папке:

 This_is_a_very_good_movie-y08iPnx_ktA.mp4
myMovie2-lKESbDzUwUg.mp4
his_is_another_movie-lKESbDzUwUg.mp4
  

Как мне извлечь первую часть строки mymovie1 из файла, указав последнюю часть, y08iPnx_ktA ? Что-то вроде:

 get_first_part("y08iPnx_kTA") #=> "This_is_a_very_good_movie"
  

Комментарии:

1. mymovie1 откуда это берется? Или вы хотите This_is_a_very_good_movie ?

2. Могут ли имена файлов содержать более одного дефиса, или вы нормализуете имена, чтобы убрать дефисы перед добавлением хэша?

Ответ №1:

Разбейте проблему на части. Метод get_first_part должен выглядеть примерно так:

  1. Используйте Dir для получения списка файлов.

  2. Выполните итерацию по каждому файлу и;

    1. Извлеките «имя» (‘This_is_a_very_good_movie’) и «тег» (‘y08iPnx_ktA’). Для каждого файла следует использовать одно и то же регулярное выражение.

    2. Если «тег» соответствует тому, что ищется, верните «name».

Удачного кодирования.


Поиграйте в REPL и получайте удовольствие 🙂

Ответ №2:

 def get_first_part(path, suffix)
  Dir.entries(path).find do |fname|
    File.basename(fname, File.extname(fname)).end_with?(suffix)
  end.split(suffix).first
end
  

Отчасти расширяет ответ от @Steve Wilhelm — за исключением того, что не использует glob (в этом нет необходимости, когда мы работаем только с именами файлов), избегает регулярных выражений и использует File.exname(fname) для File.basename вызова, поэтому вам не нужно указывать расширение файла. Также возвращает строку «This_is_a_very_good_movie» вместо массива файлов.

Это, конечно, вызовет, если файл не найден.. в этом случае, если вы просто хотите вернуть nil , если совпадение не удалось найти:

 def get_first_part(path, suffix)
  file = Dir.entries(path).find do |fname|
    File.basename(fname, File.extname(fname)).end_with?(suffix)
  end
  file.split(suffix).first if file
end
  

Ответ №3:

Можно ли это сделать чище, чем это? ПЕРЕСМОТРЕНО на основе предложения @Tin Man’s

 def get_first_part(path, suffix)
  Dir.glob(path   "*"   suffix   "*").map { |x| File.basename(x).gsub(Regexp.new("#{suffix}.*$"),'') } 
end

puts get_first_part("/path/to/files/", "-y08iPnx_kTA")
  

Комментарии:

1. 1 За хитрый трюк с использованием глобуса с карточкой while. Я бы сказал, что do/end и больше новых строк сделали бы это чище, но .. 😉 Хотя map почему?

2. Dir.glob вернул полные пути к каждому файлу. Может быть более одного файла, соответствующего шаблону. @yozloy хотел просто базовое имя без суффикса. Есть ли лучший способ сделать это?

3. OP не хочет указывать суффикс, он хочет указать подстроку. Добавьте ` ‘ *» к вашему глобусу, и вы выполните его требование.

4. Ваше решение — это вау! после того, как я сам разобрался с вашим кодом, осталось только одно место, я не уверен .gsub(Regexp.new("#{suffix}.*$")) , насколько я понимаю, если экранировать точку. итак, * повторите ‘.’ несколько раз, пока не дойдете до конца строки, но это всего лишь 1 точка в extname ‘.mp4’. то, что я думаю, это Regexp.new («#{suffix} .. * $»), для меня имеет смысл, хотя ваш код полностью работает, однако я не понимаю

5. Когда я избегаю точки (она же точка), это означает буквально соответствовать периоду. Я сделал это для того, чтобы регулярное выражение вычисляло предоставленную строку суффикса, за которой следует суффикс файла. Используя ваш пример, он найдет aaa-y08iPnx_kTA.mp4, но избегает bbb-y08iPnx_kTA-something-else.mp4.

Ответ №4:

Если имена файлов имеют только один дефис:

 path = '/Users/greg/Desktop/test'
target = 'rb'

def get_files(path, target)
  Dir.chdir(path) do
    return Dir["*#{ target }*"].map{ |f| f.split('-').first }
  end
end

puts get_files(path, 'y08iPnx_ktA')
# >> This_is_a_very_good_movie
  

Если есть несколько дефисов:

 def get_files(path, target)
  Dir.chdir(path) do
    return Dir["*#{ target }*"].map{ |f| f.split(target).first.chop }
  end
end

puts get_files(path, 'y08iPnx_ktA')
# >> This_is_a_very_good_movie
  

Если предполагается, что код выполняется изнутри каталога, содержащего файлы, то Dir.chdir его можно удалить, упростив задачу либо:

 puts Dir["*#{ target }*"].map{ |f| f.split('-').first }
# >> This_is_a_very_good_movie
  

или

 puts Dir["*#{ target }*"].map{ |f| f.split(target).first.chop }
# >> This_is_a_very_good_movie
  

Комментарии:

1. Тим, чувак, спасибо, что сообщил мне об использовании Dir[],