简体   繁体   中英

replace a string with a specfic format using regex - Ruby

This is my code below. I have some 100 text files and i want to replace numerous strings in a specific format which includes a value respective to a key in a hash map.

You can understand the scenario if you have a look at the below code.

require 'yaml'

map = YAML.load(File.open("/Documents/final.yml"))

Dir.glob('/Documents/**/*.txt') do |item|
   next if item == '.' or item == '..'
contents = File.read(item)
newFile = File.open(item, "w")
contents  = contents.gsub(/My data\(@"([^"]+)",([^,]+),([^,]+),([^,]+)\)/) {'Your data(@'+ $1 +','+ $2 +',' + $3 + ',' + map[$1] + ',' + $4 + ')'}
newFile.write(contents)
end

for some reason i get an error as below [ test2.rb is my ruby script file]

test2.rb:9:in `+': no implicit conversion of nil into String (TypeError)
from test2.rb:9:in `block (2 levels) in <main>'
from test2.rb:9:in `gsub'
from test2.rb:9:in `block in <main>'
from test2.rb:5:in `glob'
from test2.rb:5:in `<main>'

If i remove map[$1] from the code, i get the output properly.

contents  = contents.gsub(/My data\(@"([^"]+)",([^,]+),([^,]+),([^,]+)\)/) {'Your data(@'+ $1 +','+ $2 +',' + $3 + ',' + $4 + ')'}

Also if i remove the other strings and have only map[$1], i still get the expected output.

contents  = contents.gsub(/My data\(@"([^"]+)",([^,]+),([^,]+),([^,]+)\)/) { map[$1] }

But together it doesnot work.

Any help will be appreciated

To expand on @NeilSlater's answer, this would be one possible clean solution:

contents.gsub(/My data\(@"([^"]+)",([^,]+),([^,]+),([^,]+)\)/) do
  values = [$1, $2, $3, map[$1], $4].join(',')
  "Your data(@#{values})"
end

in this case, join will implicitly call to_s on the array contents. However, that means that if a value is not found in map , you will end up with an empty value, eg

Your data(@123,a,b,,c)

if you want to omit this, call compact on the array before joining it and you'll end up with

Your data(@123,a,b,c)

The value of map[$1] is nil for at least one entry in one of the files. On its own, this can be stored in an Array and output as you require. When concatenated using + it causes the error that you see.

You can force a conversion to String by using map[$1].to_s instead. For nil this will return the empty String "" , which is probably what you want.

You could also use Ruby's built-in string interpolation which does the same thing internally and is a good match to your use - the block after .gsub could be { "Your data(@#{$1},#{$2},#{$3},#{map[$1]},#{$4})" }

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