Почему Chronic неправильно анализирует четыре месяца письма?

В хронике 0.9.1 при разборе Febr 2013 Я получаю результат June 2013, Feb 2013 разбирается нормально но Febr 2013 не является.

Я думаю, что проблема в том, когда сокращение месяца имеет четыре буквы.

Мне необходимо:

  • парсить Febr 2013 в February 2013, или же
  • аннулировать Febr 2013,

Для проверки даты я использую:

Chronic.parse(params[:date]).blank?

Это ошибка? Могу ли я сделать работу Arround? Или есть правильный способ проверить это?

1 ответ

Решение

Технически это ошибка, но я больше склонен называть это дырой в их логике. Вот как http://rubydoc.info/gems/chronic/0.9.1/Chronic/Repeater.scan_for_month_names решает, что такое месяц:

# File 'lib/chronic/repeater.rb', line 38

def self.scan_for_month_names(token)
  scan_for token, RepeaterMonthName,
  {
    /^jan[:\.]?(uary)?$/ => :january,
    /^feb[:\.]?(ruary)?$/ => :february,
    /^mar[:\.]?(ch)?$/ => :march,
    /^apr[:\.]?(il)?$/ => :april,
    /^may$/ => :may,
    /^jun[:\.]?e?$/ => :june,
    /^jul[:\.]?y?$/ => :july,
    /^aug[:\.]?(ust)?$/ => :august,
    /^sep[:\.]?(t[:\.]?|tember)?$/ => :september,
    /^oct[:\.]?(ober)?$/ => :october,
    /^nov[:\.]?(ember)?$/ => :november,
    /^dec[:\.]?(ember)?$/ => :december
  }
end

Названия месяцев состоят из трех букв или всего названия.

Вы можете извлечь этот метод из исходного кода, изменить шаблоны в соответствии с вашими потребностями, затем перезаписать этот метод, а также отправить его в виде патча, чтобы твик был добавлен в будущие ревизии гема. Или вы можете изменить входящую строку, выполнив поиск трехбуквенных сокращений в начале слова и обрезав посторонние символы.


Хорошо, вот что жевать:

require 'abbrev'

MONTHS = %w[
  january
  february
  march
  april
  may
  june
  july
  august
  september
  october
  november
  december
]

MONTHS_ABBREV = Abbrev.abbrev(MONTHS)
MONTHS_REGEX = /\b(?:j(?:a(?:n(?:u(?:a(?:ry?)?)?)?)?|u(?:ly?|ne?))|s(?:e(?:p(?:t(?:e(?:m(?:b(?:er?)?)?)?)?)?)?)?|a(?:u(?:g(?:u(?:st?)?)?)?|p(?:r(?:il?)?)?)|d(?:e(?:c(?:e(?:m(?:b(?:er?)?)?)?)?)?)?|f(?:e(?:b(?:r(?:u(?:a(?:ry?)?)?)?)?)?)?|n(?:o(?:v(?:e(?:m(?:b(?:er?)?)?)?)?)?)?|o(?:c(?:t(?:o(?:b(?:er?)?)?)?)?)?|ma(?:r(?:ch?)?|y))\b/i

%w[j ja jan janu january f fe feb febr february].each do |m|
  puts "#{ m } => #{ MONTHS_ABBREV[m[MONTHS_REGEX]] }" 
end

Какие выводы:

j =>
ja => january
jan => january
janu => january
january => january
f => february
fe => february
feb => february
febr => february
february => february

Другими словами, j не уникален, так что нет никакого хита. ja уникален и связан с january, как и остальные ja... тесты. f уникален, так что хиты, как и все остальные f... тесты.

Что значит Abbrev.abbrev делать? Он разбивает передаваемые слова на минимальные уникальные строки, используемые для идентификации всего слова. Вот как это выглядит, если я использую только четыре месяца:

require 'abbrev'

MONTHS = %w[
  march
  may
  june
  july
]

MONTHS_ABBREV = Abbrev.abbrev(MONTHS)
pp MONTHS_ABBREV

В результате чего:

{"marc"=>"march",
 "mar"=>"march",
 "jun"=>"june",
 "jul"=>"july",
 "march"=>"march",
 "may"=>"may",
 "june"=>"june",
 "july"=>"july"}

Они создают замечательные начальные значения для регулярного выражения.

Откуда я взял MONTHS_REGEX? Хех... это какой-то волшебный код на Perl, использующий малоизвестный модуль Regexp:: Assemble, который мне очень не хватает в Ruby. Это страшно... нет, это... дьявольски хорошо и тесно связано с тем, как Perl делает вещи, и у меня болит голова, когда я читаю это, иначе я бы перенес это.

Другие вопросы по тегам