Ruby - Read file and print line number - ruby

This isn't going to be easy to explain and I haven't found any answers for it.
I want to be able to read .txt file in Ruby and somehow be able to print the line number.
Example:
#file.txt:
#Hello
#My name is John Smith
#How are you?
File.open("file.txt").each do |line|
puts line
puts line.linenumber
end
#First Iteration outputs
#=> Hello
#=> 1
#Second Iteration outputs
#=> My name is John Smith
#=> 2
#Third Iteration outputs
#=> How are you?
#=> 3
I hope this makes sense and I hope it's easily possible.
Thanks in advance,
Reece

Ruby, like Perl, has the special variable $. which contains the line number of a file.
File.open("file.txt").each do |line|
puts line, $.
end
Prints:
#Hello
1
#My name is John Smith
2
#How are you?
3
Strip the \n from line if you want the number on the same line:
File.open("file.txt").each do |line|
puts "#{line.rstrip} #{$.}"
end
#Hello 1
#My name is John Smith 2
#How are you? 3
As stated in comments, rather than use File.open you can use File.foreach with the benefit of autoclose at the end of the block:
File.foreach('file.txt') do |line|
puts line, $.
end
# same output...

You can use Enumerable#each_with_index:
Calls block with two arguments, the item and its index, for each item
in enum. Given arguments are passed through to each().
File.open(filename).each_with_index do |line, index|
p "#{index} #{line}"
end

Related

How do I print the line number of each line in a string?

If I have a string within c1, I can print it in a line by doing:
c1.each_line do |line|
puts line
end
I want to give the number of each line with each line like this:
c1.each_with_index do |line, index|
puts "#{index} #{line}"
end
But that doesn't work on a string.
I tried using $.. When I do that in the above iterator like so:
puts #{$.} #{line}
it prints the line number for the last line on each line.
I also tried using lineno, but that seems to work only when I load a file, and not when I use a string.
How do I print or access the line number for each line on a string?
Slightly modifying your code, try this:
c1.each_line.with_index do |line, index|
puts "line: #{index+1}: #{line}"
end
This uses with with_index method in Enumerable.
Slightly modifying #sagarpandya82's code:
c1.each_line.with_index(1) do |line, index|
puts "line: #{index}: #{line}"
end
c1 = "Hey diddle diddle,\nthe cat and the fiddle,\nthe cow jumped\nover the moon.\n"
n = 1.step
#=> #<Enumerator: 1:step>
c1.each_line { |line| puts "line: #{n.next}: #{line}" }
# line: 1: Hey diddle diddle,
# line: 2: the cat and the fiddle,
# line: 3: the cow jumped
# line: 4: over the moon.

Ruby: sub/gsub at a particular line OR before/after a pattern

I know that I can replace text as below in a file
File.write(file, File.read(file).gsub(/text/, "text_to_replace"))
Can we also use sub/gsub to:-
Replace a string on a particular line number (useful when there is a same string at different locations in a file)
Example
root#vikas:~# cat file.txt
fix grammatical or spelling errors
clarify meaning without changing it
correct minor mistakes
add related resources or links
root#box27:~#
I want to insert some text at 3rd line
root#vikas:~# cat file.txt
fix grammatical or spelling errors
clarify meaning without changing it
Hello, how are you ?
correct minor mistakes
add related resources or links
root#box27:~
Replace a string on the line just before/after matching a pattern
Example
root#vikas:~# cat file.txt
fix grammatical or spelling errors
clarify meaning without changing it
correct minor mistakes
add related resources or links
root#box27:~#
I want to search 'minor mistakes' and put text 'Hello, how are you ?' before that.
root#vikas:~# cat file.txt
fix grammatical or spelling errors
clarify meaning without changing it
Hello, how are you ?
correct minor mistakes
add related resources or links
root#box27:~
Here is the answer.
File.open("file.txt", "r").each_line do |line|
if line =~ /minor mistakes/
puts "Hello, how are you ?"
end
puts "#{line}"
end
Here is ruby one-liner.
ruby -pe 'puts "Hello, how are you ?" if $_ =~ /minor mistakes/' < file.txt
You can find this functionality in a gem like Thor. Check out the documentation for the inject_into_file method here:
http://www.rubydoc.info/github/erikhuda/thor/master/Thor/Actions#inject_into_file-instance_method.
Here is the source code for the method:
https://github.com/erikhuda/thor/blob/067f6638f95bd000b0a92cfb45b668bca5b0efe3/lib/thor/actions/inject_into_file.rb#L24-L32
If you wish to match on line n (offset from zero):
def match_line_i(fname, linenbr regex)
IO.foreach(fname).with_index { |line,i|
return line[regex] if i==line_nbr }
end
or
return scan(regex) if i==line_nbr }
depending on your requirements.
If you wish to match on a given line, then return the previous line, for application of gsub (or whatever):
def return_previous_line(fname, regex)
last_line = nil
IO.foreach(fname) do |line|
line = f.readline
return last_line if line =~ regex
last_line = line
end
end
Both methods return nil if there is no match.
Okay, as there is no such option available with sub/gsub, I am pasting here my code (with slight modifications to BMW's code) for all three options. Hopefully, this helps someone in a similar situation.
Insert text before a pattern
Insert text after a pattern
Insert text at a specific line number
root#box27:~# cat file.txt
fix grammatical or spelling errors
clarify meaning without changing it
correct minor mistakes
add related resources or links
always respect the original author
root#box27:~#
root#box27:~# cat ruby_script
puts "#### Insert text before a pattern"
pattern = 'minor mistakes'
File.open("file.txt", "r").each_line do |line|
puts "Hello, how are you ?" if line =~ /#{pattern}/
puts "#{line}"
end
puts "\n\n#### Insert text after a pattern"
pattern = 'meaning without'
File.open("file.txt", "r").each_line do |line|
found = 'no'
if line =~ /#{pattern}/
puts "#{line}"
puts "Hello, how are you ?"
found = 'yes'
end
puts "#{line}" if found == 'no'
end
puts "\n\n#### Insert text at a particular line"
insert_at_line = 3
line_number = 1
File.open("file.txt", "r").each_line do |line|
puts "Hello, how are you ?" if line_number == insert_at_line
line_number += 1
puts "#{line}"
end
root#box27:~#

My instance variable isn't holding its value

Okay, so I'm building something that takes a text file and breaks it up into multiple sections that are further divided into entries, and then puts <a> tags around part of each entry. I have an instance variable, #section_name, that I need to use in making the link. The problem is, #section_name seems to lose its value if I look at it wrong. Some code:
def find_entries
#sections.each do |section|
#entries = section.to_s.shatter(/(some) RegEx/)
#section_name = $1.to_s
puts #section_name
add_links
end
end
def add_links
puts "looking for #{#section_name} in #{#section_hash}"
section_link = #section_hash.fetch(#section_name)
end
If I comment out the call to add_links, it spits out the names of all the sections, but if I include it, I just get:
looking for in {"contents" => "of", "the" => "hash"}
Any help is much appreciated!
$1 is a global variable which can be used in later code.$n contains the n-th (...) capture of the last match
"foobar".sub(/foo(.*)/, '\1\1')
puts "The matching word was #{$1}" #=> The matching word was bar
"123 456 789" =~ /(\d\d)(\d)/
p [$1, $2] #=> ["12", "3"]
So I think #entries = section.to_s.shatter(/(some) RegEx/) line is not doing match properly. thus your first matched group contains nothing. so $1 prints nil.

What is the differences between print and puts in Ruby with example?

May be this is a duplicate question, What is the differences between print and puts in Ruby? Can I have answer with example please?
print does not add a newline at the end.. puts does.
Most other languages have similar structures too.
Java has System.out.println() and System.out.print()
C# has Console.WriteLine() and Console.Write()
Pascal had Writeln() and Write()
It's simple. puts automatically appends a newline when it prints. print prints the string without modification.
Another difference is in the number of underlying write operations. puts is (roughly) equivalent to:
STDOUT.write(str)
STDOUT.write("\n")
And print (roughly) equivalent to:
STDOUT.write(str)
So, in multithreaded environments, puts can create some weird looking stuff, like this:
Message1Messa
ge2
(blank line)
While printing a string with a concatenated newline yields:
Message1
Message2
Other than that, they're the same.
irb(main):014:0> class Person
irb(main):015:1> attr_accessor :name, :age, :gender
irb(main):016:1> end
=> nil
irb(main):017:0> person = Person.new
=> #<Person:0x2bf03e0>
irb(main):018:0> person.name = "Robert"
=> "Robert"
irb(main):019:0> person.age = 52
=> 52
irb(main):020:0> person.gender = "male"
=> "male"
irb(main):021:0> puts person
#<Person:0x2bf03e0>
=> nil
irb(main):022:0> print person
#<Person:0x2bf03e0>=> nil
irb(main):023:0> print person.name
Robert=> nil
irb(main):024:0> puts person.name
Robert
=> nil
The difference between print and puts is that puts automatically moves the output cursor to the next line (that is, it adds a newline character to start a new line unless the string already ends with a newline), whereas print continues printing text onto the same line as the previous time.
puts isn't prefixed by the name of a class or object upon which to complete the method and puts is a method made available from the Kernel module and that is included and searched by default, so usually you won’t need to use Kernel.puts to refer to it.
Kernel.puts "Hello, world!"
puts takes only one argument and is rarely followed by other methods or logic, so parentheses are not strictly necessary.
There are two major differences between puts and print in general.
1. New line
puts take every element and prints in a newline(without specifying the need of a new line character "\n" in the end)
Whereas print doesn't print each element in a new line unless the programmer explicitly specify it.
puts "Hello, Welcome to Ruby"
Output:
Hello, Welcome to Ruby
Dell-System-XPS:~/Documents/2016RoR/Ruby$
print "Hello, Welcome to Ruby"
Output:
Hello, Welcome to RubyDell-System-XPS:~/Documents/2016RoR/Ruby$
Did you notice, there is no new line after the output.
However, the new line should work when you explicitly mention the new line character like below
print "Hello, Welcome to Ruby \n"
Output:
Hello, Welcome to Ruby
Dell-System-XPS:~/Documents/2016RoR/Ruby$
2. Empty characters or NIL values
print statement prints the empty or NIL values but puts statement doesn't print them if they contain NIL values in it.
> print [nil, 33,44,55]
> [nil, 33, 44, 55] => nil
> puts [nil, 33,44,55]
> 33
> 44
> 55
=> nil
"You see the difference, there is no NIL value printed while using puts"
A comparison can be see in print vs put. For example take a look on Input & output in Ruby.

Ruby grep with line number

What could be the best way of getting the matching lines with the line numbers using Ruby's Enumerable#grep method. (as we use -n or --line-number switch with grep command).
Enumerable#grep doesn't let you do that, at least by default. Instead, I came up with:
text = 'now is the time
for all good men
to come to the aid
of their country'
regex = /aid/
hits = text.lines.with_index(1).inject([]) { |m,i| m << i if (i[0][regex]); m }
hits # => [["to come to the aid\n", 3]]
maybe something like this:
module Enumerable
def lgrep(pattern)
map.with_index.select{|e,| e =~ pattern}
end
end
This isn't elegant or efficient, but why not just number the lines before grepping?
You can kludge it in Ruby 1.8.6 like so:
require 'enumerator'
class Array
def grep_with_index(regex)
self.enum_for(:each_with_index).select {|x,i| x =~ regex}
end
end
arr = ['Foo', 'Bar', 'Gah']
arr.grep_with_index(/o/) # => [[0, 'Foo']]
arr.grep_with_index(/a/) # => [[1, 'Bar'], [2, 'Gah']]
Or if you're looking for tips on writing a grep-like utility in Ruby. Something like this should work:
def greplines(filename, regex)
lineno = 0
File.open(filename) do |file|
file.each_line do |line|
puts "#{lineno += 1}: #{line}" if line =~ regex
end
end
end
>> lines=["one", "two", "tests"]
=> ["one", "two", "tests"]
>> lines.grep(/test/){|x| puts "#{lines.index(x)+1}, #{x}" }
3, tests
To mash up the Tin Man's and ghostdog74's answers
text = 'now is the time
for all good men
to come to the aid
of their country'
regex = /aid/
text.lines.grep(/aid/){|x| puts "#{text.lines.find_index(x)+1}, #{x}" }
# => 3, to come to the aid
A modification to the solution given by the Tin Man. This snippet will return a hash having line numbers as keys, and matching lines as values. This one also works in ruby 1.8.7.
text = 'now is the time
for all good men
to come to the aid
of their country'
regex = /aid/
hits = text.lines.each_with_index.inject({}) { |m, i| m.merge!({(i[1]+1) => i[0].chomp}) if (i[0][regex]); m}
hits #=> {3=>"to come to the aid"}
Put text in a file
test.log
now is the time
for all good men
to come to the aid
of their country
Command line (alternative of grep or awk command )
ruby -ne ' puts $_ if $_=~/to the/' test.log
Try this also
ruby -na -e ' puts $F[2] if $_=~/the/' test.log
Similarly
ruby -na -e ' puts $_.split[2] if $_=~/the/' test.log
This is similar to awk command.
Another suggestion:
lines.find_index{ |l| l=~ regex }.

Resources