2

I have a following file:

old_file

new_file
  Some string.
end

Text in the middle that is not supposed to go to any of files.

new_file
  Another text.
end

How using regex can I create two files with the following content:

file1

new_file
  Some string.
end

file2

new_file
  Another text.
end

How can I get information which is between keywords 'new_file' and 'end' to write it to the file?

Michael Gaskill
  • 7,913
  • 10
  • 38
  • 43
Alex Nikolsky
  • 2,087
  • 6
  • 21
  • 36
  • 3
    If you can read the file in as one string, use [`/^new_file$.*?^end$/m`](http://rubular.com/r/MeVuqOfpyz) – Wiktor Stribiżew May 30 '16 at 08:26
  • @WiktorStribiżew Could I create several files If I read the old file once at a time? – Alex Nikolsky May 30 '16 at 08:30
  • 1
    Another way is shown here: http://stackoverflow.com/questions/6632784/ruby-print-selected-lines-of-text-in-between-2-strings – Wiktor Stribiżew May 30 '16 at 08:30
  • 1
    No idea what you mean. You get all matches first, then create files to save those texts. Your previous question showed the code you were using: you read the file line by line. See the link above to an [answer for a similar scenario](http://stackoverflow.com/a/6632803/3832970). The right answer depends on what approach you want to take, and I'd rather you posted the code you have. – Wiktor Stribiżew May 30 '16 at 08:33
  • @WiktorStribiżew My aim is just to create files each of which contains different **new_file end** block. Frankly, I don't know which approach would be more efficient in this case - reading by line or reading file at a time. – Alex Nikolsky May 30 '16 at 08:40

3 Answers3

2

If your files are not that large, you can read them in as a string, (use File.read(file_name)), and then run the following regex:

file_contents.scan(/^new_file$.*?^end$/m).select { |block| WRITE_TO_FILE_CODE_HERE }

See the regex demo

The ^new_file$.*?^end$ regex matches new_file that is a whole line content, then 0+ any characters as few as possible (incl. a newline as /m modifier is used), and then end (a whole line).

Else, you may adapt this answer here as

printing = false
File.open(my_file).each_line do |line|
  printing = true if line =~ /^new_file$/      
  puts line if printing
  printing = false if line =~ /^end$/
end

Open the file when the starting line is found, write to it where puts line is in the example above, and close when printing false occurs.

Community
  • 1
  • 1
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Great answer. Can I check everything and then accept? – Alex Nikolsky May 30 '16 at 08:58
  • 1
    Sure, take your time. – Wiktor Stribiżew May 30 '16 at 09:01
  • Виктор, You are truly great ;) I wish I knew regexp as good as you. Maybe you could bring up a couple of books? – Alex Nikolsky May 30 '16 at 09:08
  • 1
    I learnt a lot from posting regex related answers here on SO. *Mastering Regular Expressions* (O'Reilly Media) is considered the best book on regexps, however, you may get a good gist of how to use regex by completing all lessons at [regexone.com](http://regexone.com), reading stuff at [regular-expressions.info](http://regular-expressions.info) and [rexegg.com](http://rexegg.com). Practice regex at [Rubular](http://rubular.com) and [Regex101](http://regex101.com). – Wiktor Stribiżew May 30 '16 at 09:14
  • Much appreciated ;) – Alex Nikolsky May 30 '16 at 09:15
1

You can also read the file chunk by chunk by changing what constitutes a "line" in ruby:

File.open("file1.txt", "w") do |file1|
  File.open("file2.txt", "w") do |file2|
    enum = IO.foreach("old_file.txt", sep="\n\n")
    file1.puts enum.next.strip
    enum.next  #discard
    file2.puts enum.next.strip
  end #automatically closes file2
end #automatically closes file1

By designating the separator as "\n\n" ruby will read all the characters up to and including two consecutive newlines--and return that as a "line".

7stud
  • 46,922
  • 14
  • 101
  • 127
0

If that kind of format is fixed, then you may try this (new_file\n.*\nend)

JanLeeYu
  • 981
  • 2
  • 9
  • 24