Как выглядит: Date.parse («123 456 789») == пт, 3 мая 2019 г.? - PullRequest
4 голосов
/ 19 марта 2019

Название в значительной степени говорит само за себя.Я пытаюсь оценить достоверность дат из импорта CSV, но если кто-то выбирает столбец номера телефона для даты рождения, анализ даты все еще проходит

Ответы [ 3 ]

6 голосов
/ 19 марта 2019

Как это: Date.parse («123 456 789») == Пт, 3 мая 2019?

Date._parse (с подчеркиванием) возвращает необработанные данные:

Date._parse('123 456 789')
#=> {:yday=>123}

Ruby рассматривает 123 как день года, а 123-й день текущего года - 3 мая.

4 голосов
/ 19 марта 2019

Документация по Date#parse прямо заявляет:

Этот метод не работает как валидатор.

Это означает, что этот методвсеяден, он произведет дату от любого входа.Вам нужно использовать Date#iso8601 вместо:

main > Date.iso8601("2019-03-19")
#⇒ #<Date: 2019-03-19 ((2458562j,0s,0n),+0s,2299161j)>
main > Date.iso8601("123 456 789")
#⇒ ArgumentError: invalid date
0 голосов
/ 20 марта 2019

Вы (и, возможно, другие) можете найти следующий метод полезным.Я сделал следующие предположения:

  • годы должны быть четырьмя цифрами;
  • недопустимые запятые могут игнорироваться и удаляться (например, «Jan, 3 2019»);и
  • день недели можно игнорировать и удалять, даже если он недействителен для даты.

MON_NAMES = Date::MONTHNAMES.drop(1).concat(Date::ABBR_MONTHNAMES.drop(1))
  #=> ["January", "February", "March", "April", "May", "June",
  #    "July", "August", "September", "October", "November", "December",
  #    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  #    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 
MON_REGEX = /\b#{Regexp.union(MON_NAMES)}\b(?!\A)/
  # => /\b(?-mix:January|February|...|December|Jan|Feb|...|Dec)\b(?!\A)/ 
MONTH_STR_TO_NBR = MON_NAMES.each_with_index.map { |mon,i| [mon, " #{1 + (i%12)} "] }.to_h 
  #=> {"January"=>" 1 ", "February"=>" 2 ", ... , "December"=>" 12 ",
  #    "Jan"=>" 1 ", "Feb"=>" 2 ", ... , "Dec"=>" 12 "} 
DAY_REGEX = /\b#{Regexp.union(Date::DAYNAMES + Date::ABBR_DAYNAMES)}\b,?/
  #=> /\b(?-mix:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sun|Mon|Tue|Wed|Thu|Fri|Sat)\b,?/

def my_parse(date_str, locale = :US)
  a = date_str.gsub(MON_REGEX, MONTH_STR_TO_NBR).
               gsub(DAY_REGEX, '').
               gsub(/(?<!\p{Alpha})(?:st|rd|th|,)(?!\p{Alpha})/, '').
               gsub(/[-\/]/, ' ').
               strip.
               split
  return nil if a.size != 3 || a.any? { |s| s.match?(/\D/) }
  yr_idx = a.index { |s| s.size == 4 }
  return nil if yr_idx.nil? || yr_idx == 1
  yr = a.delete_at(yr_idx)
  return nil unless a.all? { |s| [1,2].include? s.size }
  if yr_idx == 0
    mon, day = a
  else
    mon, day = locale == :US ? a : a.reverse
  end
  begin
    Date.strptime("%s %s %s" % [mon, day, yr], '%m %d %Y')
  rescue ArgumentError
    nil
  end
end      

my_parse("Tue, 12th January 2019")      #=> #<Date: 2019-01-12 (...)> 
my_parse("Tue, 12th January 2019", :UK) #=> #<Date: 2019-12-01 (...)> 
my_parse("12/4/2019", :US)              #=> #<Date: 2019-04-12 (...)>
my_parse("12/4/2019", :UK)              #=> #<Date: 2019-12-04 (...)>
my_parse("Jan 12, 2019")                #=> #<Date: 2019-12-01 (...)>
my_parse("2019 Jan 23rd")               #=> #<Date: 2019-01-23 (...)> 
my_parse("Jan 2019 4")                  #=> nil 
my_parse("1/2019/4")                    #=> nil 
my_parse("1/2019/4")                    #=> nil    
my_parse("Jen 12, 2019")                #=> nil 
my_parse("3 Jan 12, 2019")              #=> nil 

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...