Using many gsub examples in Ruby

I am doing a basic translator in Ruby (1.9.3). I pull out from the local test file ("a.txt") and using gsub to replace certain matches to simulate a translation from modern English to middle / early modern English. I ran into a reading problem:

How can I make reading a lot of gsub easier? I tried using multiple lines starting with

def translate @text.gsub(/my/, 'mine') @text.gsub(/\sis\s/, ' be ') end 

but it only prints the final gsub. I can only assume that the second request overwrites the first. I would like to avoid creating a gsub giant query string and I cannot find a suitable answer.

Here is an example of my current program:

 lines = File.readlines('a.txt') @text = lines.join def translate @text.gsub(/my/, 'mine').gsub(/\sis\s/, ' be ').gsub(/y\s/, 'ye ').gsub(/t\s/, 'te ').gsub(/t\,/, 'te,').gsub(/t\./, 'te.') end puts translate 

I apologize in advance if this request seems solid. Hurrah!

+6
source share
5 answers

The second call does not cancel the first. The first call returns a copy of @text with the replacement made, but you are not doing anything with this returned value. If you want to change @text , you need to use gsub! instead gsub! . If you do not want to modify @text , then you need to bind gsub calls. For example, if you have a Hash mapping from slivu answer , this will return the translated text without actually modifying the @text instance @text :

 def translate RegexMap.inject(@text) do |string, mapping| string.gsub(*mapping) end end 

The block passed to inject is called once for each mapping (key / value pair in RegexMap ). The first time string is the value passed to inject , namely @text . After that, each subsequent call receives the return value of the previous call, passed as its string value. It’s as if you did it, but with a set of configurations it’s easier to configure:

 @text.gsub(/my/,'mine').gsub(/\sis\s/, ' be ').gsub(/y\s/,'ye ').gsub.... 
+6
source

The String#gsub method returns a new copy of the replacement string, leaving the original string unmodified. Both substitutions in your first example are completed, but the result of the first is discarded because it is not assigned to anything. The result of the second is returned as a result of the method.

If instead you use the #gsub! method #gsub! , which will change the original string with the substitution results, which will simplify the implementation of several substitutions.

 def translate @text.gsub!(/my/, 'mine') @text.gsub!(/\sis\s/, ' be ') @text end 

If you do not want to change the attribute of an object, you can start the method using text = @text.dup , and then use the text variable instead of the @text attribute for the rest of the method.

+6
source

more readable?

could you think of creating a map and using a loop in it?

 RegexMap = { /my/ => 'mine', /\sis\s/ => ' be ', /y\s/ => 'ye ', /t\s/ => 'te ', /t\,/ => 'te,', /t\./ => 'te.', } text = '123 my 456 is 123y 456t 123t, 456t.' RegexMap.each_pair {|f,t| text = text.gsub(f, t)} puts text #=> 123 mine 456 be 123ye 456te 123te, 456te. 

Update: as suggested by Mark, using gsub! avoids redundant copy / assign operations:

 RegexMap.each_pair {|f,t| text.gsub! f, t} 

Here is a working demo

+5
source

Creating the idea of ​​slivu, here is an alternative similar to Perl:

 @text = '123 my 456 is 123y 456t 123t, 456t.' def s(regex, string) @text.gsub!(regex, string) end s /my/, 'mine' s /\sis\s/, ' be ' s /y\s/, 'ye ' s /t\s/, 'te ' s /t\,/, 'te,' s /t\./, 'te.' puts @text 
0
source

If you always convert a specific template, namely words, then you can have a simple matching template, and then replace, depending on the word, with only one gsub run for the corresponding template.

 def translate @text .gsub(/[ \t]+/, " ") .gsub(/\w+/, "my" => "mine", "is" => "be", "y" => "ye", "t" => "te" ) end 

This will be much faster than repeating several times for gsub .

0
source

All Articles