我想在日期上拆分此文本,但不从字符串中删除日期:
sep 25 fri The Phenomenauts, The Atom Age, Los Pistoleros, The Shames
at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @
sep 25 fri The Holdup, The Wheeland Brothers
at the El Rey Theatre, Chico 18+ (a/a with adult) 7:30pm/8:30pm **
数组中的第一个元素是:
sep 25 fri The Phenomenauts, The Atom Age, Los Pistoleros, The Shames
at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @`
条目具有可变行数,因此我无法拆分新行。
日期格式为:
month_abbreviation + space(or two) + day_number
像这样的伪代码:
three_letter_word + whitespace(s) + one_or_two_digit_number
会奏效。
答案 0 :(得分:2)
Ruby有一个很棒的方法,它是Array(继承自Enumerable)的一部分,名为slice_before
。我会像以下一样使用它:
str = <<EOT
sep 25 fri The Phenomenauts, The Atom Age, Los Pistoleros, The Shames
at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @
sep 25 fri The Holdup, The Wheeland Brothers
at the El Rey Theatre, Chico 18+ (a/a with adult) 7:30pm/8:30pm **
EOT
MONTHS = %w[jan feb mar apr may jun jul aug sep oct nov dec]
MONTH_PATTERN = Regexp.union(MONTHS).source # => "jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec"
MONTH_REGEX = /^(?:#{ MONTH_PATTERN })\b/i # => /^(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\b/i
schedule = str.lines.slice_before(MONTH_REGEX).to_a
# => [["sep 25 fri The Phenomenauts, The Atom Age, Los Pistoleros, The Shames\n",
# " at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @\n"],
# ["sep 25 fri The Holdup, The Wheeland Brothers\n",
# " at the El Rey Theatre, Chico 18+ (a/a with adult) 7:30pm/8:30pm **\n"]]
schedule[0]
# => ["sep 25 fri The Phenomenauts, The Atom Age, Los Pistoleros, The Shames\n",
# " at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @\n"]
schedule[1]
# => ["sep 25 fri The Holdup, The Wheeland Brothers\n",
# " at the El Rey Theatre, Chico 18+ (a/a with adult) 7:30pm/8:30pm **\n"]
slice_before
对字符串不起作用,它适用于Array或Enumerator,因此第一步是使用lines
基于行尾分割字符串,这将返回一个枚举器。 slice_before
然后查看数组中的每个元素,并根据匹配MONTH_REGEX
找到的匹配创建子数组。
/^(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\b/i
基本上是说“从字符串的开头开始,找到与三个字母的月份名称匹配的单词,无论它们的字母是什么”。
因为它是用于匹配“前切片”点的正则表达式,所以很容易定制需要匹配的确切模式。在这种特殊情况下,具有前导空白行的行是连续行,换句话说,它们是次要的,而不是最重要的。偶尔会看到这种数据输出。没有前导空格的行是断行,表示新记录的开头。我可以使用/^\S/
的模式打破,这意味着“找到一条以不是空白的东西开头的行,但我觉得匹配更具体的东西,月缩写,非常有用且具体而不浪费时间在匹配过程中。/^\w{3} \d{1,2} \w{3} /
也可以工作,但由于^
因为匹配的子字符串必须出现在字符串的开头,所以它会过度,但是如果这没有意义那么请阅读Regexp在IRB中课程的文档和实验,因为它一点都不难理解。
join
如果你愿意,可以将子数组重新转换为字符串:
schedule.map(&:join)
# => ["sep 25 fri The Phenomenauts, The Atom Age, Los Pistoleros, The Shames\n at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @\n",
# "sep 25 fri The Holdup, The Wheeland Brothers\n at the El Rey Theatre, Chico 18+ (a/a with adult) 7:30pm/8:30pm **\n"]
这是我们内部使用的一种技术,用于拆分巨型配置文件,将它们分成几行并找到带有正则表达式的部分的标记。
答案 1 :(得分:1)
您指定要分割日期。因此,我没有拆分任何具有指定日期格式且无法转换为日期的字符串,包括"Sep 31 Sat"
和"Sep 26 Wed"
(后者,今年为"Sat"
)。我假设日期子字符串可以出现在字符串中的任何位置。如果你想要求他们从每一行的开头开始,那当然是一个简单的修改。
str =
"sep 25 fri The Phenomenauts, The Atom Age, Los Pistoleros, The Shames
at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @
sep 31 mon at some other place
oct 26 sat The Holdup, The Wheeland Brothers
at the El Rey Theatre, Chico 18+ (a/a with adult) 7:30pm/8:30pm **"
require 'date'
arr = str.split.
map(&:capitalize).
each_cons(3).
map { |a| a.join(' ') }.
select { |s| Date.strptime(s, '%b %d %a') rescue nil }
#=> ["Sep 25 Fri", "Oct 26 Sat"]
r = /(#{ arr.join('|') })/i
#=> /(Sep 25 Fri|Oct 26 Sat)/i
str.split(r)
#=" ["",
# "sep 25 fri",
# " The Phenomenauts, The Atom Age, Los Pistoleros, The Shames\n\
# at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @\n sep 31\
# mon at some other place \n ",
# "oct 26 sat",
# " The Holdup, The Wheeland Brothers\n at the El Rey Theatre,\
# Chico 18+ (a/a with adult) 7:30pm/8:30pm **"]
要避免返回数组开头和结尾的空字符串,请使用:
str.split(r).delete_if(&:empty?)
答案 2 :(得分:0)
假设OP的描述:
three_letter_word + whitespace(s)+ one_or_two_digit_number将起作用
是对的,
text.split(/(?=\w{3} +\d{1,2})/)
答案 3 :(得分:0)
有12个月零7天,所以你可以选择它们:
text = <<txt
sep 25 fri The Phenomenauts, The Atom Age, Los Pistoleros, The Shames
at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @
sep 25 The Holdup, The Wheeland Brothers
at the El Rey Theatre, Chico 18+ (a/a with adult) 7:30pm/8:30pm **
txt
text.split(/((?:jan|feb|mar|apr|may|jun|ju|aug|sep|oct|nov|dec)\s+[12]?\d)/).each{|part|
p part
}
p '-------------'
text.split(/((?:jan|feb|mar|apr|may|jun|ju|aug|sep|oct|nov|dec)\s+[12]?\d(?:\s*(?:mon|tue|wed|thu|fri|sat|sun))?)/).each{|part|
p part
}
结果:
""
"sep 25"
" fri The Phenomenauts, The Atom Age, Los Pistoleros, The Shames\n at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @\n"
"sep 25"
" The Holdup, The Wheeland Brothers\n at the El Rey Theatre, Chico 18+ (a/a with adult) 7:30pm/8:30pm **\n"
"-------------"
""
"sep 25 fri"
" The Phenomenauts, The Atom Age, Los Pistoleros, The Shames\n at Jub Jubs, 71 S Wells Avenue, Reno, NV 21+ 8pm *** @\n"
"sep 25"
" The Holdup, The Wheeland Brothers\n at the El Rey Theatre, Chico 18+ (a/a with adult) 7:30pm/8:30pm **\n"
正则表达式的一些细节:
(?:....)
避免匹配的部分成为结果的一部分($ 1,$ 2 ......)(?:
,并且会成为结果的一部分。()
,则会在结果中删除匹配项。[123]?\d
检查可选的1,2或3和另一个号码。这将允许日期数字,如32,33 ...... 答案 4 :(得分:0)
由于您需要拆分每个日期,因此您需要确定匹配过程中正则表达式引擎的位置。您可以使用前瞻?=
,然后捕获您想要的令牌,以实现此目的。
例如,这种模式(?=[a-zA-Z]{3}\s+\d{1,2}\s+[a-zA-Z]{6,9})
这里,正则表达式引擎将位于任何单词的起始位置,其中包含三个字母,后跟一个或多个空格,一个或两个数字,一个或多个空格,以及一个6到9的单词信件,例如。 sep 25 Friday
。在此示例中,正则表达式引擎位于s
中的sep
之前。使用这些知识,您现在可以使用您选择的任何编程语言拆分String。
line.split(/?=[a-zA-Z]{3}\s+\d{1,2}\s+[a-zA-Z]{6,9}/);
?=:
这是一个前瞻性,与要捕获的正则表达式令牌之前的位置相匹配。
[a-zA-Z]{3}:
匹配3个字,因为月份是单词而不是数字,例如sep
\s+\d{1,2}:
匹配一个或多个空格,后跟一个或两个数字
\s+[a-zA-Z]{6,9}:
匹配一个或多个空格,后跟至少6个单词,最多9个单词,因为一周中数字最少的一天是Friday
(6个字母)和最高为Wednesday
(9个字母)
答案 5 :(得分:-2)
我可以看到除了每条记录的第一行之外的行都缩进了几个空格,因此您可以使用str.split(/\n(?!\s+)/)
进行拆分。