2016-12-21 3 views
0

У меня есть строка, которая выглядит так: log/archive/2016-12-21.zip, и мне нужно извлечь часть даты.Извлечь дату из строки пути файла

До сих пор я попробовал эти решения:

1) ["log/archive/2016-12-21.zip"].map{|i|i[/\d{4}-\d{2}-\d{2}/]}.first 
2) "log/archive/2016-12-21.zip".to_date 
3) "log/archive/2016-12-21.zip".split("/").last.split(".").first 

есть лучший способ сделать это?

+1

, если точка должна всегда приходит только в последнем, то вы можете попробовать это '«Журнал/архив/2016-12-21.zip». split (/[\/.]/)[- 2] ' –

+0

Да, точка всегда будет навсегда – Thorin

+0

Даже это не самое простое решение, я всегда буду с регулярным выражением (\/(\ d {4} - \ d {2} - \ d {2}) \. zip). Причина в том, что вы можете протестировать его с совпадением, и вы обязательно обнаружите, изменилась ли структура строки. Я не знаю, как ведет себя номер 2, но я бы не пошел с номером 3, так как он может оценивать строки без дат вообще ... –

ответ

4

Вы можете использовать File.basename пропускание расширения:

File.basename("log/archive/2016-12-21.zip", ".zip") 
# => "2016-12-21" 

Если вы хотите, чтобы значение быть Date, просто использовать Date.parse, чтобы преобразовать строку в `Date.

require 'date' 
Date.parse(File.basename("log/archive/2016-12-21.zip", ".zip")) 
+0

Если строки из каталога читаются, это было бы очень хорошо решение. Но мой вопрос из интереса, что произойдет, если в имени файла нет действительной даты? например, «log/archive/12-21.zip» –

+0

@DoktorOSwaldo в этом случае вместо того, чтобы передавать значение непосредственно в 'Date.parse', вам придется обрабатывать разбор по своему усмотрению и составлять дату. –

+0

Да, но знаете ли вы поведение рубина в этом случае, не получится ли оно и даст исключение? или это будет что-то вроде 1970-12-21? –

0
require 'date' 

def pull_dates(str) 
    str.split(/[\/.]/).map { |s| Date.strptime(s, '%Y-%m-%d') rescue nil }.compact 
end 

pull_dates "log/archive/2016-12-21.zip" 
    #=> [#<Date: 2016-12-21 ((2457744j,0s,0n),+0s,2299161j)>] 
pull_dates "log/2016-12-21/archive.zip" 
    #=> [#<Date: 2016-12-21 ((2457744j,0s,0n),+0s,2299161j)>] 
pull_dates "log/2016-12-21/2016-12-22.zip" 
    #=> [#<Date: 2016-12-21 ((2457744j,0s,0n),+0s,2299161j)>, 
    # #<Date: 2016-12-22 ((2457745j,0s,0n),+0s,2299161j)>] 
pull_dates "log/2016-12-21/2016-12-32.zip" 
    #=> [#<Date: 2016-12-21 ((2457744j,0s,0n),+0s,2299161j)>] 
pull_dates "log/archive/2016A-12-21.zip" 
    #=> [] 
pull_dates "log/archive/2016/12/21.zip" 
    #=> [] 

Если вы хотите строку с датой, а не объект даты, измените метод следующим образом.

def pull_dates(str) 
    str.split(/[\/.]/). 
     each_with_object([]) { |s,a| 
     a << s if (Date.strptime(s, '%Y-%m-%d') rescue nil)} 
end 

pull_dates "log/archive/2016-12-21.zip" 
    #=> ["2016-12-21"] 
0

Пожалуйста, попробуйте этот

"log/archive/2016-12-21.zip".scan(/\d{4}-\d{2}-\d{2}/).pop 
=> "2016-12-21" 

Если формат даты является недействительным, он возвращает ноль.

Пример: -

"log/archive/20-12-21.zip".scan(/\d{4}-\d{2}-\d{2}/).pop 
      ^^ 
=> nil 

Надеется, что это помогает.

1

Это регулярное выражение должно охватывать большинство случаев. Это позволяет дополнительно нецифру между годом, месяцем и днем:

require 'date' 

def extract_date(filename) 
    if filename =~ /((?:19|20)\d{2})\D?(\d{2})\D?(\d{2})/ then 
    year, month, day = $1.to_i, $2.to_i, $3.to_i 
    # Do something with year, month, day, or just leave it like this to return an array : [2016, 12, 21] 
    # Date.new(year, month, day) 
    end 
end 

p extract_date("log/archive/2016-12-21.zip") 
p extract_date("log/archive/2016.12.21.zip") 
p extract_date("log/archive/2016:12:21.zip") 
p extract_date("log/archive/2016_12_21.zip") 
p extract_date("log/archive/20161221.zip") 
p extract_date("log/archive/2016/12/21.zip") 
p extract_date("log/archive/2016/12/21") 
#=> Every example returns [2016, 12, 21] 
Смежные вопросы