Ruby: if statement using regexp and boolean operator - ruby

I'm learning Ruby and have failed to make a compound 'if' statement work. Here's my code (hopefully self explanatory)
commentline = Regexp.new('^;;')
blankline = Regexp.new('^(\s*)$')
if (line !~ commentline || line !~ blankline)
puts line
end
the variable 'line' is gotten from reading the following file:
;; alias filename backupDir
Prog_i Prog_i.rb ./store
Prog_ii Prog_ii.rb ./store
This fails and I'm not sure why. Basically I want the comment lines and blank lines to be ignored during the processing of the lines in the file. Thanks for your help.

you need to use an AND
basically you want not (blank or comment) which turns into not blank and not comment after applying DeMorgan
if (line !~ commentline && line !~ blankline)
puts line
end
or
unless(line ~= commentline || line ~= blankline)
puts line
end
depending on which you find more readable

You can write this much more terse, as
puts DATA.readlines.reject{|each|each =~ /^;;|^\s*$/}
__END__
;; alias filename backupDir
Prog_i Prog_i.rb ./store
Prog_ii Prog_ii.rb ./store

This is your code:
commentline = Regexp.new('^;;')
blankline = Regexp.new('^(\s*)$')
if (line !~ commentline || line !~ blankline)
puts line
end
and how I'd write the same thing:
[
';; alias filename backupDir',
'',
'Prog_i Prog_i.rb ./store',
'Prog_ii Prog_ii.rb ./store'
].each do |line|
puts line if (!line[/^(?:;;)?$/])
end
Which outputs:
;; alias filename backupDir
Prog_i Prog_i.rb ./store
Prog_ii Prog_ii.rb ./store

Related

matching a double-quote via quote vs pattern

Why does check_char1 fail to find the double-quote?
#!/usr/bin/env ruby
line = 'hello, "bob"'
def check_char1(line, _char)
puts "check_char1 found #{_char} in #{line}" if line =~ /_char/
end
check_char1(line, '"')
def check_char2(line, _char)
puts "check_char2 found #{_char.inspect} in #{line}" if line =~ _char
end
check_char2(line, /"/)
...and can it be made to work using line =~ /_char/? (How should the double-quote be passed to the method?)
If _char is just a string (i.e. no regex pattern matching needed) then just use String#include?
if line.include?(_char)
If you must use a regex for this then Regexp.escape is your friend:
if line =~ /#{Regexp.escape(_char)}/
if line =~ Regexp.new(Regexp.escape(_char))
and if you want _char to be treated like a regex (i.e. '.' matches anything) then drop the Regexp.escape:
if line =~ /#{_char}/
if line =~ Regexp.new(_char)
In check_char1, _char in /_char/ is treated as a literal, not a variable. You need /#{_char}/.
If _char were treated as variable how could one enter a literal in a regex that was the name of a variable, method or constant?

Get the first word of a file into a variable

I have a txt file and I want to extract only the first word of a line which contains the characters 'ath'.
File.open("myfile.txt").readlines.each do |line|
if line =~ /ath/
line.split.first
puts line
$line = line.chomp
puts "Ok"
else
nil
end
end
line.split.first only works if the first word of the line is a match, because when I do the same in irb:
"im here to ask someting easy".split.first
The output is 'im'.
If the first word in a line contains ath at any point
if line =~ /^\S*ath\S*/

Ruby - Reading a file causes an extra line while printing

How can I avoid a new line when I use puts line + "test"
Example code:
File.open("test.txt", "r") do |f|
f.each_line do |line|
puts line + "test" #=>line1\ntest
#puts "test" + line #=> testline1
end
end
When I use:
puts "test" + line`
It shows:
testline1
(line1 being the only thing in the test.txt)
However,
puts line + "test"
looks like:
test
line1
Is there anyway of stopping it from producing the extra line?
If you want to strip out the newline, use String#chomp to take care of it.
http://apidock.com/ruby/v1_9_3_392/String/chomp
puts line.chomp + "test"
Use String#strip to strip out all the leading and trailing whitespace characters (including new line):
puts line.strip + "test"
# => line1test
To delete only the trailing whitespaces, you can use String#rstrip:
puts line.rstrip + "test"
# => line1test

Removing lines in a text file based on the beginning characters

I have an email message which looks like this:
Hey how are you?
On Saturday sender#example.com wrote:
> something
> On Friday sender#example.com wrote:
>> previous thing
How would I remove the lines that start with > as well as lines that include email#example.com wrote
Should I even keep the "someone wrote" part as that could remove legitimate lines, maybe only removing that line if it's the last line.
I'm trying this out:
message_filtered = message_txt.to_s.split("\n").each do |m|
if m[0] != ">" then
return m
end
end
puts message_filtered
I could push m to an array and then join that array with \n but i'm trying a shorter way.
Try
message_filtered = message_txt.lines.reject { |line|
line[0] == '>' || line =~ YOUR_EMAIL_REGEXP
}.join('\n')
To remove lines that start with > you can use:
message_filtered = message_txt.gsub(/(^>.+)/, '') # should work but not tested
my proposition:
message_filtered = '';
message_txt.to_s.lines {|line| message_filtered << line unless line[0] == '>' }
How about this,
> str = "Hey how are you?\nOn Saturday sender#example.com wrote:\n> something\n> On Friday sender#example.com wrote:\n>> previous thing"
> str.split("\n").reject{|msg| msg =~ /^>/ || msg =~ /#example.com/}.join("\n")
=> "Hey how are you?"
String.gsub with a simple regex can do this:
text = <<EOT
Hey how are you?
On Saturday sender#example.com wrote:
> something
> On Friday sender#example.com wrote:
>> previous thing
EOT
puts text.gsub(/(?:^>|On \w+ sender#example.com wrote:).+\n/m, '')
# => "Hey how are you?\n\n"

Building multi-line strings, programmatically, in Ruby

Here's something I often do when programming:
code = ''
code << "next line of code #{something}" << "\n"
code << "another line #{some_included_expression}" << "\n"
Is there some better way than having << "\n" or + "\n" on every line? This seems quite inefficient.
I'm interested in Ruby solutions, in particular. I'm thinking something like
code = string.multiline do
"next line of code #{something}"
"another line #{some_included_expression}"
end
If you're looking to build a block of text, the easy way to do it is to just use the % operator. For example:
code = %{First line
second line
Third line #{2 + 2}}
'code' will then be
"First line\n second line\n Third line 4"
This would be one way:
code = []
code << "next line of code #{something}"
code << "another line #{some_included_expression}"
code.join("\n")
Use <<- operator:
code = <<-CODE
var1 = "foo"
var2 = "bar"
CODE
It would work for you to just embed ...\n" in your strings, I suppose. Here is a fun way to do it:
class String
def / s
self << s << "\n"
end
end
then
f = "" # => ""
f / 'line one' # => "line one\n"
f / 'line two' # => "line one\nline two\n"
f / 'line three' # => "line one\nline two\nline three\n"
This would enable something like:
"" / "line 1" / "line 2" / "line 3" # => "line 1\nline 2\nline 3\n"
Or even:
f/
"line one"/
"line two"/
"line three" # => "line one\nline two\nline three\n"
Here's a method presented here:
str = <<end.margin
|This here-document has a "left margin"
|at the vertical bar on each line.
|
| We can do inset quotations,
| hanging indentions, and so on.
end
This is accomplished by using this:
class String
def margin
arr = self.split("\n") # Split into lines
arr.map! {|x| x.sub!(/\s*\|/,"")} # Remove leading characters
str = arr.join("\n") # Rejoin into a single line
self.replace(str) # Replace contents of string
end
end
I guess the question with this is: does the lack of portability / presence of monkey patching make this solution bad.
What's wrong with:
code = "next line of code #{something}\n"+
"another line #{some_included_expression}"
You could place your multi-line text in a file, and use ERB to parse it (note ERB is included with Ruby)
require 'erb'
multi_line_string = File.open("multi_line_string.erb", 'r').read
template = ERB.new(multi_line_string)
template.result(binding)
(ERB can access variables from a Binding, an object that provides access to the instance methods and variables that are owned by another object. By setting it to "binding" it points to itself)
Documentation here.

Resources