简体   繁体   中英

Ruby Regex gsub! without using if

First of all, full disclosure, I am working on a homework assignment. The example I'm giving is not the exact problem, but will help me understand what I need to do. I'm not looking for a spoon-fed answer but to understand what is going on.

I am trying to take a string such as:

"The Civil War started in 1861."
"The American Revolution started in 1775."

In this example I would like to return the same string, but with the appropriate century in parenthesis after

"The Civil War started in 1861. (Nineteenth Century)"
"The American Revolution started in 1775. (Eighteenth Century)"

I am able to group what I need using the following regex

text.gsub!(/([\w ]*)(1861|1775).?/, '\1\2 (NOT SURE HERE)')

It would be easy using grouping to say if \\2 == 1861 append appropriate century, but the specifications say no if statements may be used and I am very lost. Also, the alternation I used in this example only works for the 2 years listed and I know that a better form of range-matching would have to be used to catch full centuries as opposed to those 2 single years.

Firstly - how to remove the hardcoding of the years:

text.gsub!(/([\w ]*)([012]\d{3}).?/, '\1\2 (NOT SURE HERE)')

This should handle things for the next ~1k years. If you know for a fact that the dates are restricted to given periods, you can be more specific.


For the other part - the century is just the first two digits plus one. So split the year in two and increment.

text.gsub(/[\w ]*([012]\d)\d\d.?/) do |sentence|
  "#{sentence} (#{$1.next}th Century)"
end

Note the usage of String#gsub with block due to the fact that we need to perform a transformation on one of the matched groups.


Update: if you want the centuries to be in words, you could use an array to store them.

ordinals = %w(
  First Second Third Fourth Fifth Sixth Seventh Eighth Ninth Tenth Eleventh
  Twelfth Thirteenth Fourteenth Fifteenth Sixteenth Seventeenth Eighteenth
  Nineteenth Twentieth Twenty–First
)

text.gsub(/[\w ]*([012]\d)\d\d.?/) do |sentence|
  "#{sentence} (#{ordinals[$1.to_i]} Century)"
end

Update (2): Assuming you want to replace something completely different and you can't take advantage of number niceties like in the centuries example, implement the same general idea, just use a hash instead of array:

replacements = {'cat' => 'king', 'mat' => 'throne'}

"The cat sat on the mat.".gsub(/^(\w+ )(\w+)([\w ]+ )(\w+)\.$/) do
  "#{$1}#{replacements[$2]}#{$3}#{replacements[$4]}."
end

Assuming the year is between 1 and 2099, you might do it as follows.

YEAR_TO_CENTURY = (1..21).to_a.zip(%w| First Second Third Fourth Fifth Sixth
  Seventh Eighth Ninth Tenth Eleventh Twelfth Thriteenth Fourteenth Fifteenth
  Sixteenth Seventeenth Eighteenth Nineteenth Twentieth Twentyfirst | ).to_h
  #=> { 1=>"First", 2=>"Second", 3=>"Third", 4=>"Fourth", 5=>"Fifth", 6=>"Sixth",
  #     7=>"Seventh", 8=>"Eighth", 9=>"Ninth", 10=>"Tenth", 11=>"Eleventh",
  #    12=>"Twelfth", 13=>"Thriteenth", 14=>"Fourteenth", 15=>"Fifteenth",
  #    16=>"Sixteenth", 17=>"Seventeenth", 18=>"Eighteenth", 19=>"Nineteenth",
  #    20=>"Twentieth", 21=>"Twentyfirst" }

def centuryize(str)
  str << " (%s Century)" % YEAR_TO_CENTURY[(str[/\d+(?=\.)/].to_i/100.0).ceil]
end

centuryize "The American Revolution started in 1775."
  #=> "The American Revolution started in 1775. (Eighteenth Century)" 
centuryize "The Battle of Hastings took place in 1066."
  #=> "The Battle of Hastings took place in 1066. (Eleventh Century)" 
centuryize "Nero played the fiddle while Rome burned in AD 64."
  #=> "Nero played the fiddle while Rome burned in AD 64. (First Century)"

It would be easier if we could write "19th" century.

def centuryize(str)
  century = (str[/\d+(?=\.)/].to_i/100.0).ceil
  suffix = 
  case century
  when 1, 21 then "st"
  when 2     then "nd"
  when 3     then "rd"
  else            "th"
  end
  "%s (%d%s Century)" % [str, century, suffix]
end

centuryize "The American Revolution started in 1775."
  # => "The American Revolution started in 1775. (18th Century)" 
centuryize "The Battle of Hastings took place in 1066."
  #=> "The Battle of Hastings took place in 1066. (11th Century)" 
centuryize "Nero played the fiddle while Rome burned in AD 64."
  #=> "Nero played the fiddle while Rome burned in AD 64. (1st Century)" 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM