it
February 10, 2023
Задача: Текст в дату
Написать функцию, переводящую строку вида
'1991 years 1 month 8 days' в дату.
1) в единственном/множественном числе.
3) не все компоненты обязательны, например '1975 year 14 days'
4) порядок компонентов может меняться, например '10 day 4 month 2000 year'
require 'byebug' require 'date' require 'rspec/autorun' def text_to_date(text) return Date.new(0,1,1) unless text.is_a? String setup = { # 0 год существует year: {regex: /\s*(\s*(?'year'\d+)\s+(?i)(years?))\s*/, default: 0}, # 0 месяц не существует month: {regex: /\s*(?'month'\b([1-9]|1[0-2])\b)\s+(?i)(months?)\s*/, default: 1}, # 0 день не существует day: {regex: /\s*(?'day'\b[1-9]|[12][0-9]|3[01]\b)\s+(?i)days?\s*/, default: 1} } date_parts = {} find_date_parts = lambda { |group_name, regex, default| (regex.match(text)&.[](group_name) || default).to_i } setup.each { |key, value| date_parts[key] = find_date_parts.call(key, value[:regex], value[:default]) } return Date.new(date_parts[:year], date_parts[:month], date_parts[:day]) end puts text_to_date('2020 years 1 month 4 days') describe 'text_to_date' do it 'normal' do expect(text_to_date('2020 years 1 month 4 days')).to eq(Date.new(2020,1,4)) end it 'case sensitive' do expect(text_to_date('2025 YeArS 1 MoNthS 15 DaYs')).to eq(Date.new(2025,1,15)) end it 'only year' do expect(text_to_date('5 years')).to eq(Date.new(5,1,1)) end it 'only month' do expect(text_to_date('5 month')).to eq(Date.new(0,5,1)) end it 'only day' do expect(text_to_date('7 days')).to eq(Date.new(0,1,7)) end it 'year and days' do expect(text_to_date('50 years 7 days')).to eq(Date.new(50,1,7)) end it 'year and month' do expect(text_to_date('50 years 7 months')).to eq(Date.new(50,7,1)) end it 'month and day' do expect(text_to_date('7 months 7 days')).to eq(Date.new(0,7,7)) end it 'mix dates' do expect(text_to_date('7 months 7 years 5 days')).to eq(Date.new(7,7,5)) expect(text_to_date('7 days 7 years 5 month')).to eq(Date.new(7,5,7)) end it 'plural year' do expect(text_to_date('7 year')).to eq(Date.new(7,1,1)) expect(text_to_date('7 years')).to eq(Date.new(7,1,1)) end it 'plural month' do expect(text_to_date('7 month')).to eq(Date.new(0,7,1)) expect(text_to_date('7 months')).to eq(Date.new(0,7,1)) end it 'plural day' do expect(text_to_date('7 day')).to eq(Date.new(0,1,7)) expect(text_to_date('7 days')).to eq(Date.new(0,1,7)) end it 'more whitespaces' do expect(text_to_date(' 2020 years 1 month 4 days ')).to eq(Date.new(2020,1,4)) expect(text_to_date(' 2020 years ')).to eq(Date.new(2020,1,1)) expect(text_to_date(' 5 month ')).to eq(Date.new(0,5,1)) expect(text_to_date(' 1 day ')).to eq(Date.new(0,1,1)) end it '1-31 days' do (1..31).each do |day| expect(text_to_date("2020 years 1 month #{day} days")).to eq(Date.new(2020,1,day)) end end it '1-12 month' do (1..12).each do |month| expect(text_to_date("2020 years #{month} months 2 days")).to eq(Date.new(2020,month,2)) end end it '0-2023 years' do (0..2050).each do |year| expect(text_to_date("#{year} years 2 months 2 days")).to eq(Date.new(year,2,2)) end end it '32 days not exist' do expect(text_to_date('2020 years 1 month 32 days')).to eq(Date.new(2020,1,1)) end it '13 month not exist' do expect(text_to_date('2020 years 13 month 4 days')).to eq(Date.new(2020,1,4)) end it 'nothing found' do expect(text_to_date('nothing')).to eq(Date.new(0,1,1)) expect(text_to_date(nil)).to eq(Date.new(0,1,1)) end end