2014-10-09 4 views
0

Ruby on Rails 응용 프로그램을 사용하고 있습니다. 응용 프로그램에서 하나의 장소에서 나는 API를 호출하는 내게 문자열을 Up 4.35% from Oct to Nov 반환합니다. 내 요구 사항은 내가 이것을 Up 4.35% from October to November으로 표시해야하는 사용자 인터페이스에 표시 할 때입니다.Ruby에서 문자열에서 월 이름을 추출하십시오.

누군가 어떻게 말해 줄 수 있습니까?

+0

문자열 형식은 예제와 같이 항상 월을 포함합니까? –

답변

2

Date::MONTHNAMES 당신을 도울 수 있습니다.

dates = Date::MONTHNAMES.compact.map { |m| [m[0..2], m] }.to_h 

을 그런 다음 다른 곳을 사용합니다 : 그들은 달의 3 문자 단축 버전이 항상 있다면, 당신은 도움이되는 해시를 만들 수

text = 'Up 4.35% from Oct to Nov' 
text.gsub(/#{dates.keys.join('|')}/, dates) 
=> "Up 4.35% from October to November" 
+1

Date :: MONTHNAMES와 좋은 아이디어가 있지만 더 나은 솔루션을 위해 MikDiet의 대답에 @ toro2k의 의견을 결합합니다. –

+0

사실. 그 (것)들을 사용하기 위하여 새롭게하십시오. –

+0

'dates.keys.join ('|')'에주의하십시오. –

2

gsub을 사용할 수 있습니다.

"Up 4.35% from Oct to Nov".gsub(/Oct|Nov/) do |s| 
    {'Oct' => 'October', 'Nov' => 'November'}[s] 
end 
# => "Up 4.35% from October to November" 
+3

해시를'gsub'의 두 번째 인수로 전달할 수 있습니다. 블록을 사용할 필요가 없습니다. 'abc'.gsub (/ a | b /,'a '=>'x ','b '=> 'y') # => 'xyc''. – toro2k

0
def replace(string) 
    string.gsub("Jan", "January").gsub("Feb", "February").gsub("Mar", "March").gsub("Apr", "April").gsub("Jul", "July").gsub("Aug", "August").gsub("Sep", "September").gsub("Oct", "October").gsub("Nov", "November").gsub("Dec", "December") 
end 

str = "Up 4.35% from Oct to Nov" 

을하고 마지막에, 단지 함수를 호출 :

그냥 모든 개월 내 예제를 확장

replace(str) 
1

String#sub 당신이

이 시도해야 할 것입니다 :

a = "Up 4.35% from Oct to Nov" 
a.sub('Oct', 'October').sub('Nov', 'November') # you can continue with other months 
#=> "Up 4.35% from October to November" 
1

사람들은 gsub이 특별한 관심을 지불하지 않습니다 능력 때문에,이 묵상 :

SHORT_TO_LONG_MONTH_NAMES = %w[ 
    January 
    February 
    March 
    April 
    May 
    June 
    July 
    August 
    September 
    October 
    November 
    December 
].map{ |m| [m[0, 3], m] }.to_h 
# => {"Jan"=>"January", "Feb"=>"February", "Mar"=>"March", "Apr"=>"April", "May"=>"May", "Jun"=>"June", "Jul"=>"July", "Aug"=>"August", "Sep"=>"September", "Oct"=>"October", "Nov"=>"November", "Dec"=>"December"} 

SHORT_TO_LONG_MONTH_NAMES_REGEX = /\b(?:#{ Regexp.union(SHORT_TO_LONG_MONTH_NAMES.keys).source })\b/ 
# => /\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/ 

str = 'Up 4.35% from Oct to Nov' 

str.gsub(SHORT_TO_LONG_MONTH_NAMES_REGEX, SHORT_TO_LONG_MONTH_NAMES) 
# => "Up 4.35% from October to November" 

빠른 검색을 수행하고 문서로 대체하는 매우 간결한 방법으로 출력 결과를 스트리핑 :

SHORT_TO_LONG_MONTH_NAMES = Hash[%w[ 
    January 
    February 
    March 
    April 
    May 
    June 
    July 
    August 
    September 
    October 
    November 
    December 
].map{ |m| [m[0, 3], m] }] 
# => {"Jan"=>"January", "Feb"=>"February", "Mar"=>"March", "Apr"=>"April", "May"=>"May", "Jun"=>"June", "Jul"=>"July", "Aug"=>"August", "Sep"=>"September", "Oct"=>"October", "Nov"=>"November", "Dec"=>"December"} 

는 정규식 패턴 생성을 깨는 :
SHORT_TO_LONG_MONTH_NAMES = %w[ 
    January 
    February 
    March 
    April 
    May 
    June 
    July 
    August 
    September 
    October 
    November 
    December 
].map{ |m| [m[0, 3], m] }.to_h 

SHORT_TO_LONG_MONTH_NAMES_REGEX = /\b(?:#{ Regexp.union(SHORT_TO_LONG_MONTH_NAMES.keys).source })\b/ 

str = 'Up 4.35% from Oct to Nov' 

str.gsub(SHORT_TO_LONG_MONTH_NAMES_REGEX, SHORT_TO_LONG_MONTH_NAMES) 
# => "Up 4.35% from October to November" 

이전 루비가 to_h 그래서 대신이 사용할 수없는

SHORT_TO_LONG_MONTH_NAMES_REGEX = /\b(?:#{ Regexp.union(SHORT_TO_LONG_MONTH_NAMES.keys).source })\b/ 
  • \b 단어 휴식 또는 낱말 경계, 낱말이 시작하거나 끝나는 곳 의미. "단어"는 문자 집합 [a-zA-Z0-9_], AKA \w이며 단어 분리는 이전 단어가 아닌 문자와 단어 문자 사이의 구분선입니다. 그렇게하지 않으면 모든 종류의 인간 비참함의 뿌리입니다. 하위 문자열은 \b없이 일치하므로 모든 종류의 흥미로운 대체물을 얻을 수 있습니다.
  • (?:...)은 일련의 대체 패턴을 찾는 좋은 방법 인 비 캡처 그룹을 정의합니다.이 경우 3 자의 단축 된 월 이름 목록입니다.
  • Regexp.union은 배열 (이 경우 해시 키)을 사용하여 패턴의 OR 기호 인 |으로 구분하는 유용한 방법입니다. 기본적으로 이것은 어떤 키도 일치 할 수 있음을 의미합니다.
  • source은 매우 중요한 부분입니다.이를 제외하면, 컴파일 된 정규 표현식 인 Regexp.union의 결과는 충돌하는 검색을 유발할 수있는 관련 플래그와 함께 문자열로 보간됩니다. 다음의 차이점을 고려하십시오.

    /foo/i # => /foo/i 
    /#{ /foo/i }/ # => /(?i-mx:foo)/ 
    /foo/i.source # => "foo" 
    /#{ /foo/i.source }/ # => /foo/ 
    

    첫 번째 문자는 대소 문자를 구분하지 않습니다. 두 번째는 대소 문자를 구분하는 패턴이며 대소 문자를 구분하는 패턴입니다. 그러나 (?i-mx:은 내부적으로 무시합니다. 그것이 당신이 정말로 원하는 것이 확실하지 않다면 그것은 기다리는 중에 벌레입니다.

    source은 플래그없이 패턴의 문자열 버전을 반환하므로 최종 결과는 실제로 기대했던 것입니다.

나는 그 전에 물었다. 그리고 그것은 추적하는 주요한 고통이었다.

마지막으로, Date 클래스에는 미리 정의 된 상수가 있으므로 위와 같이 해시를 정의하지 않아도됩니다. 즉 무슨 일이 일어 났는지는 분명하게했지만, 편의를 위해 당신은 같은 일을 수행 할 수 있습니다

require 'date' 

Date::ABBR_MONTHNAMES.zip(Date::MONTHNAMES)[1..-1].to_h # => {"Jan"=>"January", "Feb"=>"February", "Mar"=>"March", "Apr"=>"April", "May"=>"May", "Jun"=>"June", "Jul"=>"July", "Aug"=>"August", "Sep"=>"September", "Oct"=>"October", "Nov"=>"November", "Dec"=>"December"} 
Hash[Date::ABBR_MONTHNAMES.zip(Date::MONTHNAMES)[1..-1]] # => {"Jan"=>"January", "Feb"=>"February", "Mar"=>"March", "Apr"=>"April", "May"=>"May", "Jun"=>"June", "Jul"=>"July", "Aug"=>"August", "Sep"=>"September", "Oct"=>"October", "Nov"=>"November", "Dec"=>"December"} 

/\b(?:#{ Regexp.union(Date::ABBR_MONTHNAMES[1..-1]).source }\b)/ # => /\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec\b)/ 

공지 사항 샘플에서 [1..-1]의 사용. 그 이유는 배열에 첫 번째 값을위한 nil이 포함되어 있기 때문입니다. 0을 기준으로하지 않고 배열을 기반으로하여 조회의 즐거움을 얻으려고하지만 배열에 패턴을 사용하려는 경우 Ruby 울부 짖음을 만들 수 있습니다.

관련 문제