Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/52.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何从rails中的字符串识别一组日期_Ruby On Rails_Ruby_Regex_String_Gem - Fatal编程技术网

Ruby on rails 如何从rails中的字符串识别一组日期

Ruby on rails 如何从rails中的字符串识别一组日期,ruby-on-rails,ruby,regex,string,gem,Ruby On Rails,Ruby,Regex,String,Gem,我有以下字符串 "sep 04 apr 06" "29th may 1982" "may 2006 may 2008" "since oct 11" 输出 "September 2004 and April 2006" "29 May 1982" "May 2006 and May 2008" "October 2011" 有没有办法从这些字符串中获取日期。我使用了gem“dates\u from\u string”,但它无法从第一个场景中正确获取日期 您可以这样使用该类: DateTime

我有以下字符串

"sep 04 apr 06"
"29th may 1982"
"may 2006 may 2008"
"since oct 11"
输出

"September 2004 and April 2006"
"29 May 1982"
"May 2006 and May 2008"
"October 2011"
有没有办法从这些字符串中获取日期。我使用了gem“dates\u from\u string”,但它无法从第一个场景中正确获取日期

您可以这样使用该类:

DateTime.parse('sep 04 apr 06')
它输出日期时间对象:

#<DateTime: 2006-04-04T00:00:00+00:00 ((2453830j,0s,0n),+0s,2299161j)>
#
当您说“不幸的是,我无法预测日期将采用何种格式”时,您可以使用方法,这意味着您实际上需要“自然语言解析”。这是核心Date或DateTime对象不能也不应该做的事情

因此,您需要解析字符串,以便以可理解的格式将它们呈现给更严格的解析器。比如
DateTime.parse('sep04')
。对于您的示例,可以简单到:

datestring = 'sep 04 apr 06'
matches = datestring.match(/[a-z]{3}\s\d{2,4}/)
if matches.many?
  matches.map{|m| Date.parse(m) }.join(' and ')
else
  Date.parse(datestring)
end
但是,当您需要真正的自然语言解析时,请查看。它有各种各样奇特的解析器,比如
Chronic.parse('summer')


编辑:仔细检查,它似乎也只能识别一个字符串,因此您的示例
'sep 04 apr 06'
仍然需要一些预处理。

我采取的方法如下:

require 'date'

def pull_dates(str)
  arr = str.split
  dates = []
  while arr.size > 1
    if arr.size > 2
      a = depunc(arr[0,3])
      if date?(a, PERM3)
        dates << a.join(' ')
        arr.shift(3)
        next
      end
    end
    a = depunc(arr[0,2])
    if date?(a, PERM2)
      dates << a.join(' ')
      arr.shift(2)
      next
    end
    arr.shift
  end
  dates
end
  • 将字符串分成一个单词数组
  • 如果数组包含少于两个单词,则返回包含找到的所有日期字符串的数组;否则,请转至步骤3
  • 如果数组至少包含三个单词,且前三个单词表示日期,请保存它,删除数组中的前三个单词,然后重复步骤2;否则,请转至步骤4
  • 如果前两个单词表示日期,则保存该日期,删除数组中的前两个单词并重复步骤2;否则,请转至步骤5
  • 删除数组中的第一个单词并转至步骤2
  • 我使用class方法搜索日期
    strtime
    使用格式字符串。例如,
    “%d%b%Y”
    搜索月份的日期,后跟空格,后跟(不区分大小写)三个字符的月份缩写(“Jan”、“Feb”、“Dec”),后跟四位数的年份。(我最初考虑使用,但不充分区分日期。)< /P> 代码

    我首先生成月、日和年的所有
    strtime
    格式字符串:

    MON = %w{ %b %B } # '%b' for 'Jan', '%B' for 'January'
    YR  = %w{ %y %Y } # '%y' for '11', '%Y' for 2011
    DAY = %w{ %d }    # '4', '04' or '28' 
    
    PERM3 = MON.product(YR, DAY).
                flat_map { |arr| arr.permutation(3).to_a }.
                map { |arr| arr.join(' ') }
      #=> ["%b %y %d", "%b %d %y", "%y %b %d", "%y %d %b", "%d %b %y", "%d %y %b",
      #    "%b %Y %d", "%b %d %Y", "%Y %b %d", "%Y %d %b", "%d %b %Y", "%d %Y %b",
      #    "%B %y %d", "%B %d %y", "%y %B %d", "%y %d %B", "%d %B %y", "%d %y %B",
      #    "%B %Y %d", "%B %d %Y", "%Y %B %d", "%Y %d %B", "%d %B %Y", "%d %Y %B"] 
    
    PERM2 = MON.product(YR).
                concat(MON.product(DAY)).
                flat_map { |arr| arr.permutation(2).to_a }.
                map { |arr| arr.join(' ') }               
      #=> ["%b %y", "%y %b", "%b %Y", "%Y %b", "%B %y", "%y %B",
      #    "%B %Y", "%Y %B", "%b %d", "%d %b", "%B %d", "%d %B"] 
    
    然后,我对日和月以及月和年的排列做同样的处理:

    MON = %w{ %b %B } # '%b' for 'Jan', '%B' for 'January'
    YR  = %w{ %y %Y } # '%y' for '11', '%Y' for 2011
    DAY = %w{ %d }    # '4', '04' or '28' 
    
    PERM3 = MON.product(YR, DAY).
                flat_map { |arr| arr.permutation(3).to_a }.
                map { |arr| arr.join(' ') }
      #=> ["%b %y %d", "%b %d %y", "%y %b %d", "%y %d %b", "%d %b %y", "%d %y %b",
      #    "%b %Y %d", "%b %d %Y", "%Y %b %d", "%Y %d %b", "%d %b %Y", "%d %Y %b",
      #    "%B %y %d", "%B %d %y", "%y %B %d", "%y %d %B", "%d %B %y", "%d %y %B",
      #    "%B %Y %d", "%B %d %Y", "%Y %B %d", "%Y %d %B", "%d %B %Y", "%d %Y %B"] 
    
    PERM2 = MON.product(YR).
                concat(MON.product(DAY)).
                flat_map { |arr| arr.permutation(2).to_a }.
                map { |arr| arr.join(' ') }               
      #=> ["%b %y", "%y %b", "%b %Y", "%Y %b", "%B %y", "%y %B",
      #    "%B %Y", "%Y %B", "%b %d", "%d %b", "%B %d", "%d %B"] 
    
    然后,我进行以下工作:

    require 'date'
    
    def pull_dates(str)
      arr = str.split
      dates = []
      while arr.size > 1
        if arr.size > 2
          a = depunc(arr[0,3])
          if date?(a, PERM3)
            dates << a.join(' ')
            arr.shift(3)
            next
          end
        end
        a = depunc(arr[0,2])
        if date?(a, PERM2)
          dates << a.join(' ')
          arr.shift(2)
          next
        end
        arr.shift
      end
      dates
    end
    
    date?
    确定三元素字符串还是两元素字符串
    arr
    表示日期。我首先从
    arr
    中获取一个“已清理”字符串,然后搜索适用的
    strtime
    格式字符串(参数
    perm
    ),寻找一个显示已清理字符串可以转换为日期的字符串

    def date?(arr, perm)
      clean = to_str_and_clean(arr)
      perm.find do |s|
        begin
          d = Date.strptime(clean, s)
          return true
        rescue
          false 
        end
      end
      false
    end
    
    to_str_和_clean
    返回一个已清除的字符串,该字符串已删除标点,并在日期的数字表示之后返回字符串,如
    'st'
    'nd'
    'rd'
    'th'

    def to_str_and_clean(arr)
      str = arr.map { |s| s[0][/\d/] ? s.to_i.to_s : s }.join(' ').tr('.?!,:;', '')
    end
    
    示例

    让我们试试看

    str =
    "Bubba sighted a flying saucer on sep 04 2013 and again in apr 06. \
    Greta was born on 29th may 1982. Hey, may 2006 may 2008 are two years apart.\
    We have been at loose ends since oct 11 of this year."
    
    pull_dates(str)
      #=> ["sep 04 2013", "apr 06", "29th may 1982", "may 2006 may", "oct 11"] 
    

    正如你所看到的,这并不完美。需要进行一些调整,但这可能会让您开始。

    但这对“DateTime.parse”(“may 2006-may 2008”)”不起作用,将抛出无效的日期错误:但这是两个不同的日期。2004年9月和2006年4月。事实上,如果你想让它工作,你需要将这两个日期分开。你必须使用正则表达式来分割包含两个或更多日期的字符串。至于解析通常已知的日期,我的答案有一些附加值。-->可能是因为他们中的一个能够处理第一个场景,他们只确定了一个日期。第一个场景,这让人困惑。您想在两个日期之间设置一个范围,还是将属于Sep MOUNT或Apr的日期分隔开?您可以使用date parse rails控制台获得以下输出,但它将忽略从输入日期算起的一个月。parse(“Sep 04 Apr 06”)=>2006年4月4日星期二,这些输入字符串来自何处?您可以更改它们吗?strtime需要格式作为参数,不幸的是,我无法预测日期的格式。这非常有用,谢谢。