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
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需要格式作为参数,不幸的是,我无法预测日期的格式。这非常有用,谢谢。