谁能帮帮我?我有一个字符串格式:10 mins - 20 mins
或1 min - 10 mins
或10 mins - 1 hour
或10 mins - 1 hour 30 mins
或10 mins - 2 hours
或10 mins - 2 hours 30 mins
。我想为所有格式创建一个正则表达式,但我不能:失望:。请帮助我,非常感谢。
上述所有格式的正则表达式。
我可能会先在破折号上分割,然后使用相同的正则表达式匹配两边的组件。
。
"1 hour 10 mins - 3 hours".split(/s+-s+/, 2).map do |s|
s.scan(
/
d+ s+ mins
| d+ s+ hour(?=s?)
| d+ s+ hour(?=s?)
s+
d+ s+ min(?=s?)
/x
)
end
# => [["1 hour", "10 mins"], ["3 hour"]]
"1 hour 10 mins - 40 mins".split(/s+-s+/, 2).map do |s|
s.scan(
/
d+ s+ mins
| d+ s+ hour(?=s?)
| d+ s+ hour(?=s?)
s+
d+ s+ min(?=s?)
/x
)
end
# [["1 hour", "10 mins"], ["40 mins"]]
我假设:
- 每个字符串在负号左边只包含分钟(不包含小时);和
- 小时(如有)在1到9之间。
这些假设与问题中给出的例子是一致的。
然后可以使用字符串#match和MatchData#named_capture与正则表达式
rgx = /(?<lmin>(?:[1-9]|[1-5]d)) mins? - (?:(?<hr>[1-9]) hours?(?: (?<rminwhr>g<lmin>) mins?)?|(?<rminwohr>g<lmin>) mins?)/
提取感兴趣的值。让我们用问题中给出的例子来试一试。
["10 mins - 20 mins",
"1 min - 10 mins",
"10 mins - 1 hour",
"10 mins - 1 hour 30 mins",
"10 mins - 2 hours",
"10 mins - 2 hours 30 mins"].each do |str|
m = str.match(rgx)
puts str
puts "str.match(rgx) = #{m.inspect}"
puts "captures = #{m.named_captures}"
puts
end
显示如下。
10 mins - 20 mins
str.match(rgx) = #<MatchData "10 mins - 20 mins" lmin:"20" hr:nil rminwhr:nil rminwohr:"20">
captures = {"lmin"=>"20", "hr"=>nil, "rminwhr"=>nil, "rminwohr"=>"20"}
1 min - 10 mins
str.match(rgx) = #<MatchData "1 min - 10 mins" lmin:"10" hr:nil rminwhr:nil rminwohr:"10">
captures = {"lmin"=>"10", "hr"=>nil, "rminwhr"=>nil, "rminwohr"=>"10"}
10 mins - 1 hour
str.match(rgx) = #<MatchData "10 mins - 1 hour" lmin:"10" hr:"1" rminwhr:nil rminwohr:nil>
captures = {"lmin"=>"10", "hr"=>"1", "rminwhr"=>nil, "rminwohr"=>nil}
10 mins - 1 hour 30 mins
str.match(rgx) = #<MatchData "10 mins - 1 hour 30 mins" lmin:"30" hr:"1" rminwhr:"30" rminwohr:nil>
captures = {"lmin"=>"30", "hr"=>"1", "rminwhr"=>"30", "rminwohr"=>nil}
10 mins - 2 hours
str.match(rgx) = #<MatchData "10 mins - 2 hours" lmin:"10" hr:"2" rminwhr:nil rminwohr:nil>
captures = {"lmin"=>"10", "hr"=>"2", "rminwhr"=>nil, "rminwohr"=>nil}
10 mins - 2 hours 30 mins
str.match(rgx) = #<MatchData "10 mins - 2 hours 30 mins" lmin:"30" hr:"2" rminwhr:"30" rminwohr:nil>
captures = {"lmin"=>"30", "hr"=>"2", "rminwhr"=>"30", "rminwohr"=>nil}
lmin
读取"负号左几分钟;rminwhr
(rminwohr
)读取"分钟"到带(不带)小时的负号右侧。
可以在这里看到正则表达式的演示。将光标悬停在正则表达式上,可以看到表达式各部分的功能说明。这些结果显示在PCRE正则表达式引擎上,但它们对于Ruby的正则表达式引擎(Oniguruma)也是一样的。
我们可以将正则表达式写成自由空格模式以使其自文档化。
/
(?<lmin> # begin capture group 'lmin'
(?: # begin non-capture group
[1-9] # match a digit other than zero
| # or
[1-5]d # match a digit between 1 and 5, followed by a digit
) # end non-capture group
) # end capture group 'lmin'
[ ]mins? # match a space followed by 'min', 's' optional
[ ]-[ ] # match ' - '
(?: # begin non-capture group
(?<hr> # begin capture group 'hr'
[1-9] # match a digit other than zero
) # end capture group 'hr'
[ ]hours? # match a space followed by 'hour', 's' optional
(?: # begin a non-capture group
[ ] # match a space
(?<rminwhr> # begin capture group 'rminwhr'
g<lmin> # invoke subexpression 'lmin'
) # end capture group 'rminwhr'
[ ]mins? # match a space followed by 'min', 's' optional
) # end non-capture group
? # make the preceding non-capture group optional
| # or
(?<rminwohr> # begin capture group 'rminwohr'
g<lmin> # invoke subexpression 'lmin'
) # end capture group 'rminwohr'
[ ]mins? # match a space followed by 'min', 's' optional
) # end non-capture group
/x # invoke free-spacing regex definition mode
g<lmin>
导致在该位置重用用于创建名为lmin
的命名捕获组的代码。这被称为"子表达式"。或";subrouting"。有关说明,请搜索"子表达式"。在Regexp。子表达式的使用减少了表达式的大小,使其更容易阅读并减少了错误的机会,特别是在将来修改表达式时。
请注意,在自由间距模式下,作为表达式一部分的空格必须以某种方式加以保护,以防止它们在解析表达式之前被剥离。我选择将每个字符放在一个字符类中,但是还有其他方法可以做到这一点(例如,转义空格字符)。