2016-12-01 74 views
2

的字符串是: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我想不通爲什麼。有任何想法嗎?

+0

可以肯定一看這裏,一個真棒工具來快速檢查您的正則表達式:http://rubular.com – Roger

+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文檔「命名捕獲組「。

+0

額外補充說:「好玩」使用塊'String#match'形式:) – engineersmnky

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

0

下面是使用正則表達式命名的分組和一個簡單的哈希查找另一種解決方案:在正則表達式

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