5

The following code is a line in an xml file:

<appId>455360226</appId>

How can I replace the number between the 2 tags with another number using ruby?

thisiscrazy4
  • 1,905
  • 8
  • 35
  • 58

4 Answers4

15

There is no possibility to modify a file content in one step (at least none I know, when the file size would change). You have to read the file and store the modified text in another file.

replace="100"
infile = "xmlfile_in"
outfile = "xmlfile_out"
File.open(outfile, 'w') do |out|
  out << File.open(infile).read.gsub(/<appId>\d+<\/appId>/, "<appId>#{replace}</appId>")
end  

Or you read the file content to memory and afterwords you overwrite the file with the modified content:

replace="100"
filename = "xmlfile_in"
outdata = File.read(filename).gsub(/<appId>\d+<\/appId>/, "<appId>#{replace}</appId>")

File.open(filename, 'w') do |out|
  out << outdata
end  

(Hope it works, the code is not tested)

knut
  • 27,320
  • 6
  • 84
  • 112
  • Hey, so if the new data is shorter then the old data the end of the old data will still be in your file leaving you with a corrupt file. – medmonds Aug 18 '15 at 20:39
  • @medmonds No. My solution rewrite the complete file. The problem you describe is why I wrote _at least none I know, when the file size would change_. If the file size changes, then the file would be corrupt. That's why there is no solution in one step. – knut Aug 19 '15 at 10:25
6

You can do it in one line like this:

IO.write(filepath, File.open(filepath) {|f| f.read.gsub(//<appId>\d+<\/appId>/, "<appId>42</appId>"/)})

IO.write truncates the given file by default, so if you read the text first, perform the regex String.gsub and return the resulting string using File.open in block mode, it will replace the file's content in one fell swoop.

I like the way this reads, but it can be written in multiple lines too of course:

IO.write(filepath, File.open(filepath) do |f|
    f.read.gsub(//<appId>\d+<\/appId>/, "<appId>42</appId>"/)
  end
)
Steve Benner
  • 1,679
  • 22
  • 26
2
replace="100"
File.open("xmlfile").each do |line|
  if line[/<appId>/ ]
     line.sub!(/<appId>\d+<\/appId>/, "<appId>#{replace}</appId>")
  end
  puts line
end
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • This looks like it worked in irb but if I go and open the actual file it doesn't look like anything changed. Is this all the code to it? Or do I have to save something? – thisiscrazy4 Sep 03 '11 at 04:17
  • when you execute the script, use the redirection operator `>` to save to another file. – ghostdog74 Sep 03 '11 at 07:11
1

The right way is to use an XML parsing tool, and example of which is XmlSimple.

You did tag your question with regex. If you really must do it with a regex then

s = "Blah blah <appId>455360226</appId> blah"
s.sub(/<appId>\d+<\/appId>/, "<appId>42</appId>")

is an illustration of the kind of thing you can do but shouldn't.

Community
  • 1
  • 1
Ray Toal
  • 86,166
  • 18
  • 182
  • 232