正则表达式的麻烦

时间:2016-12-01 19:36:22

标签: ruby regex

字符串为:1/9/2017

我的正则表达式是:/([0-9]{1,2})\/[0-9]{1,2}\/([0-9]{4})/

这是我的代码行:

  def session_formatter(string)
    if string =~ /([0-9]{1,2})\/[0-9]{1,2}\/([0-9]{4})/
      year = $2
      if $1 =~ /8|9|10|11/
        "Fall " + year
      elsif $1 =~ /1|2|3/
        "Spring " + year
      else
        string
      end
    end
  end

我已1/9/2017返回而不是Spring 2017,我无法弄清楚原因。有任何想法吗?

3 个答案:

答案 0 :(得分:2)

而不是处理我使用的正则表达式:

str = '1/9/2017'

mm, dd, yyyy = str.split('/')
case mm.to_i
when 1, 2, 3
  "Spring #{yyyy}"
when 8, 9, 10
  "Fall #{yyyy}"
else
  str
end
# => "Spring 2017"

正则表达式很棒,但人们喜欢使用它们,因此忽略了更简单地完成任务的方式。并不是所有的东西都是等待用正则锤击打的指甲。

/上的拆分可以降低视觉噪音,使​​用to_i可以更轻松地阅读和理解when正在做的事情。

或者,使用Date类,它具有各种优点:

require 'date'

str = '1/9/2017'

date = Date.strptime(str, '%m/%d/%Y')
case date.month
when 1, 2, 3
  "Spring #{date.year}"
when 8, 9, 10
  "Fall #{date.year}"
else
  str
end
# => "Spring 2017"

我使用strptime因为日期格式在全球范围内并不一致。作为一种国际语言,Ruby使用最常见的格式dd / mm / yyyy用于Date.parse(...),这在解析基于美国的日期时可能会遇到问题。而strptime让我强迫解析器使用基于美国的mm / dd / yyyy形式:

require 'date'

Date.strptime('31/12/2001', '%d/%m/%Y') # => #<Date: 2001-12-31 ((2452275j,0s,0n),+0s,2299161j)>
Date.strptime('31/12/2001', '%m/%d/%Y') # => ArgumentError: invalid date

# ~> ArgumentError
# ~> invalid date

请注意,第一个示例成为此特定问题的牺牲品。处理日期时,如果您允许用户输入日期作为自由格式字符串,那么您知道用户来自哪里非常重要,因此您至少可以猜测这些值的顺序。更好,更多用户 - 友好的解决方案是使用具有某种日期选择器的表单,这会强制订单进入您的代码所期望的。错误地处理日期会导致涉及时间或金钱的计算造成重大破坏,您只是不希望发生这种情况。

如果日期是文件中文本的一部分,则处理起来会更容易一些,因为它应该一致地格式化,但顺序仍然很重要。

如果确实坚持使用模式,我会这样做:

str = '1/9/2017'
/(?<mm>[0-9]{1,2})\/[0-9]{1,2}\/(?<yyyy>[0-9]{4})/ =~ str 

mm # => "1"
yyyy # => "2017"

case mm.to_i
when 1, 2, 3
  "Spring #{yyyy}"
when 8, 9, 10
  "Fall #{yyyy}"
else
  str
end
# => "Spring 2017"

或者,为了增加乐趣:

str = '1/9/2017'
matches = /(?<mm>[0-9]{1,2})\/[0-9]{1,2}\/(?<yyyy>[0-9]{4})/.match(str)

mm, yyyy = matches[:mm], matches[:yyyy]

case mm.to_i
when 1, 2, 3
  "Spring #{yyyy}"
when 8, 9, 10
  "Fall #{yyyy}"
else
  str
end
# => "Spring 2017"

请参阅Ruby的Regexp文档,了解“命名捕获组”。

答案 1 :(得分:1)

您正在使用后续的正则表达式检查重写$1变量。将其分配给单独的变量并用于进一步检查。

def session_formatter(string)
    if string =~ /([0-9]{1,2})\/[0-9]{1,2}\/([0-9]{4})/
      year = $2
      month = $1
      if month =~ /8|9|10|11/
        "Fall " + year
      elsif month =~ /1|2|3/
        "Spring " + year
      else
        string
      end
    end
  end

请参阅Ruby demo

答案 2 :(得分:0)

这是在regex中使用命名分组和简单哈希查找的另一种解决方案:

TIME_OF_YEAR = { 'Winter' => [12,1,2], 
                 'Spring' => [3,4,5],
                 'Summer' =>  [6,7,8], 
                 'Fall' => [9,10,11]}

def session_formatter(string)
   string.match(/(?<month>[0-9]{1,2})\/[0-9]{1,2}\/(?<year>[0-9]{4})/) do |m|
     TIME_OF_YEAR.detect {|_,v| v.include? (m[:month].to_i)}.first + " #{m[:year]}"
   end
end

dates = ["1/9/2017", "2/9/2017", "3/9/2017", "4/9/2017", "5/9/2017", "6/9/2017", "7/9/2017", "8/9/2017",
"9/9/2017", "10/9/2017", "11/9/2017", "12/9/2017"]

puts dates.map {|d| session_formatter(d)}

这使用正则表达式中的命名分组和匹配的块形式,允许您以简洁的方式查找TIME_OF_YEAR哈希中的一年中的时间。

Demo