#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
должен выглядеть примерно так:
-
Используйте Dir для получения списка файлов.
-
Выполните итерацию по каждому файлу и;
-
Извлеките «имя» (‘This_is_a_very_good_movie’) и «тег» (‘y08iPnx_ktA’). Для каждого файла следует использовать одно и то же регулярное выражение.
-
Если «тег» соответствует тому, что ищется, верните «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[],