From: Dan George Date: 2007-09-20T19:25:16+09:00 Subject: Re: YAML & readlines & modify text files On Sep 20, 11:51 am, Stefano Crocco wrote: > Alle gioved� 20 settembre 2007, Dan George ha scritto: > > > > > On Sep 20, 1:41 am, Stefano Crocco wrote: > > > Alle gioved� 20 settembre 2007, Dan George ha scritto: > > > > On Sep 20, 12:39 am, Stefano Crocco wrote: > > > > > Alle mercoled� 19 settembre 2007, Dan George ha scritto: > > > > > > CATEG being another line inside the text files... and the problem > > > > > > might be because the Name-line isn't always above the Link-line. I > > > > > > could have n lines between or below, what I'm trying to say is that > > > > > > I don't know where the Name-line is inside the texts files. > > > > > > This changes everything. I assumed (according to the example lines > > > > > you posted) that each Link-line had the corresponding Name-line above > > > > > it. But, if there isn't a relation between the position of the two > > > > > kind of lines, how can you know what to put in the link line? I mean, > > > > > what is the relation which connects a Link-line and the corresponding > > > > > Name-line? Since (from what you say now) the position of the two kind > > > > > of lines are random (as far as this problem is concerned, at any > > > > > rate) are you able, given a single Link-line, to understand which is > > > > > the corresponding Name-line? If yes, how? Whithout knowing this, I > > > > > can't help you. > > > > > > Stefano > > > > > All I can say is that in each text file there will only be one Name- > > > > line and one Link-line. The only connection between this 2 lines is > > > > that the Link uses the shorter version of what is written in the Name- > > > > line (i.e. if the Name-line: New York the Link line will use NY) > > > > > Isn't it possible to read the Name-line, take the correspond value > > > > from the YAML file, store it in a variable (string?) inside the code > > > > and then use it in the Link-line, when going to the next text file > > > > read again the Name-line and take the value from YAML and so on... > > > > If each file contains only one Name-line and one instance of the > > > corresponding Link-line, this should work: > > > > require 'yaml' > > > > lnk='blabla.something.' > > > op = '&=bla' > > > hash = File.open('name.yaml'){|f| YAML.load f} > > > > Dir.glob('**/*.txt').each do |f| > > > lines = File.readlines f > > > name = nil > > > link_idx = nil > > > lines.each_with_index do |l, i| > > > if l.match(/Name-line:\s+(.*)$/) then name $1 > > > elsif l.match(/Link-line/) then link = i > > > end > > > break if name and link_idx > > > end > > > if name > > > rep = hash[name] > > > if rep > > > lines[link_idx]="Link-line: #{lnk}#{rep}#{op}" > > > File.open(f, 'w'){|of| of.write lines} > > > else puts "name.yaml doesn't contain an entry for #{name} (file > > > #{f})" end > > > else puts "Couldn't find a Name line in file #{f}" > > > end > > > end > > > > For each file, it loops each line looking for a Name-line or a Link-line. > > > When it finds the former, it stores the name in the name variable; when > > > it finds the latter, it stores its index in the link_idx variable. When > > > both are found, the loop stops (no point in examining the remaining > > > lines). If a name has been found and it corresponds to an entry in the > > > hash, the line with index link_idx is replaced with a new one (I removed > > > the call to gsub!, since we're rebuilding the entire line, but you can > > > put it back, if you need it), then the array is written to the file. If > > > the Name-line wasn't found, or if the hash doesn't contain an entry for > > > it, an error message is printed on screen and the next file is processed. > > > > I hope this helps > > > > Stefano > > > Thanks for your reply Stefano! > > > I had to do: > > link_idx = nil.to_i > > otherwise I would get this error: `[]': no implicit conversion from > > nil to integer (TypeError) > > > And it seems to be working but if I use this: > > lines[link_idx]="Link-line: #{lnk}#{rep}#{op}" > > the Name-line is removed and is replaced by the "Link-line: > > #{lnk}#{rep}#{op}" but the old Link-line = 0 is kept too. > > > If I use > > lines[link_idx].gsub!(/Link-line.*/, 'Link-line: '+lnk+rep > > +op) > > nothing happends, no errors, no modified files, no nothing. > > > I don't see anything wrong with the gsub! so what might be the problem? > > Another couple of mistakes on my part, I'm afraid. This should work > > require 'yaml' > > lnk='blabla.something.' > op = '&=bla' > hash = File.open('name.yaml'){|f| YAML.load f} > > Dir.glob('**/*.txt').each do |f| > lines = File.readlines f > name = nil > link_idx = nil > lines.each_with_index do |l, i| > #added missing = between name and $1 > if l.match(/Name-line:\s+(.*)$/) then name = $1 > #changed link = i to link_idx = i > elsif l.match(/Link-line/) then link_idx = i > end > break if name and link_idx > end > #checking that also link_idx is not nil > if name and link_idx > rep = hash[name] > if rep > lines[link_idx]="Link-line: #{lnk}#{rep}#{op}" > File.open(f, 'w'){|of| of.write lines} > else puts "name.yaml doesn't contain an entry for the name #{name}" > end > #changed the error message > else puts "Name or Link line are missing in file #{f}" > end > end > > Stefano Thank you Stefano! Works like a charm now :) This part (#added missing = between name and $1 ) I figured it too but I should have been more careful about this part "#checking that also link_idx is not nil" I liked the #comments part, thank you! Now I'm gonna try and search for text files inside a zip archive and modify them and then zip them back together. Stefano, how long have you been using Ruby because you seem to know a lot of stuff and I was wondering how long it will take me to know half of what you know?