How do I call a variable from an array? Trying to make this:
hello_world = "Hey"
array = [ '#{hello_world} ho' ]
array.each do |a|
puts a
end
say ["Hey ho"] instead of ["\#{hello_world} ho"].
Do as below -
hello_world = "Hey"
array = [ "#{hello_world} ho" ]
array # => ["Hey ho"]
array.each do |a|
p a
end
# >> "Hey ho"
Single-quoted strings disabling interpolation, but double-quote strings allow interpolation.
Remember - Interpolation may be disabled by escaping the “#” character or using single-quote strings:
'#{1 + 1}' #=> "\#{1 + 1}"
Related
It appears that using gsub inside a (double quoted) heredoc does not evaluate the result of gsub, as follows:
class Test
def self.define_phone
class_eval <<-EOS
def _phone=(val)
puts val
puts val.gsub(/\D/,'')
end
EOS
end
end
Test.define_phone
test = Test.new
test._phone = '123-456-7890'
# >> 123-456-7890
# >> 123-456-7890
The second puts should have printed 1234567890, just as it would in this case:
'123-456-7890'.gsub(/\D/,'')
# => "1234567890"
What is going on inside the heredoc?
The problem is with the \D in the regex. It will be evaluated when the heredoc is evaluated as a string, which results in D:
"\D" # => "D"
eval("/\D/") #=> /D/
On the other hand, \D inside a single quote will not be evaluated as D:
'\D' # => "\\D"
eval('/\D/') # => /\D/
So wrap the heredoc terminator EOS in a single quote to achieve what you want:
class Test
def self.define_phone
class_eval <<-'EOS'
def _phone=(val)
puts val
puts val.gsub(/\D/,'')
end
EOS
end
end
Test.define_phone
test = Test.new
test._phone = '123-456-7890'
# >> 123-456-7890
# >> 1234567890
Reference
If you run the above code without the wrapped EOS, gsub will try to replace "D" (literally) in the val. See this:
test._phone = '123-D456-D7890DD'
# >> 123-D456-D7890DD
# >> 123-456-7890
When using scan in Ruby, we are searching for a block within a text file.
Sample file:
sometextbefore
begin
sometext
end
sometextafter
begin
sometext2
end
sometextafter2
We want the following result in an array:
["begin\nsometext\nend","begin\nsometext2\nend"]
With this scan method:
textfile.scan(/begin\s.(.*?)end/m)
we get:
["sometext","sometext2"]
We want the begin and end still in the output, not cut off.
Any suggestions?
You may remove the capturing group completely:
textfile.scan(/begin\s.*?end/m)
See the IDEONE demo
The String#scan method returns captured values only if you have capturing groups defined inside the pattern, thus a non-capturing one should fix the issue.
UPDATE
If the lines inside the blocks must be trimmed from leading/trailing whitespace, you can just use a gsub against each matched block of text to remove all the horizontal whitespace (with the help of \p{Zs} Unicode category/property class):
.scan(/begin\s.*?end/m).map { |s| s.gsub(/^\p{Zs}+|\p{Zs}+$/, "") }
Here, each match is passed to a block where /^\p{Zs}+|\p{Zs}+$/ matches either the start of a line with 1+ horizontal whitespace(s) (see ^\p{Zs}+), or 1+ horizontal whitespace(s) at the end of the line (see \p{Zs}+$).
See another IDEONE demo
Here's another approach, using Ruby's flip-flop operator. I cannot say I would recommend this approach, but Rubiests should understand how the flip-flop operator works.
First let's create a file.
str =<<_
some
text
at beginning
begin
some
text
1
end
some text
between
begin
some
text
2
end
some text at end
_
#=> "some\ntext\nat beginning\nbegin\n some\n text\n 1\nend\n...at end\n"
FName = "text"
File.write(FName, str)
Now read the file line-by-line into the array lines:
lines = File.readlines(FName)
#=> ["some\n", "text\n", "at beginning\n", "begin\n", " some\n", " text\n",
# " 1\n", "end\n", "some text\n", "between\n", "begin\n", " some\n",
# " text\n", " 2\n", "end\n", "some text at end\n"]
We can obtain the desired result as follows.
lines.chunk { |line| true if line =~ /^begin\s*$/ .. line =~ /^end\s*$/ }.
map { |_,arr| arr.map(&:strip).join("\n") }
#=> ["begin\nsome\ntext\n1\nend", "begin\nsome\ntext\n2\nend"]
The two steps are as follows.
First, select and group the lines of interest, using Enumerable#chunk with the flip-flop operator.
a = lines.chunk { |line| true if line =~ /^begin\s*$/ .. line =~ /^end\s*$/ }
#=> #<Enumerator: #<Enumerator::Generator:0x007ff62b981510>:each>
We can see the objects that will be generated by this enumerator by converting it to an array.
a.to_a
#=> [[true, ["begin\n", " some\n", " text\n", " 1\n", "end\n"]],
# [true, ["begin\n", " some\n", " text\n", " 2\n", "end\n"]]]
Note that the flip-flop operator is distinguished from a range definition by making it part of a logical expression. For that reason we cannot write
lines.chunk { |line| line =~ /^begin\s*$/ .. line =~ /^end\s*$/ }.to_a
#=> ArgumentError: bad value for range
The second step is the following:
b = a.map { |_,arr| arr.map(&:strip).join("\n") }
#=> ["begin\nsome\ntext\n1\nend", "begin\nsome\ntext\n2\nend"]
Ruby has some great methods in Enumerable. slice_before and slice_after can help with this sort of problem:
string = <<EOT
sometextbefore
begin
sometext
end
sometextafter
begin
sometext2
end
sometextafter2
EOT
ary = string.split # => ["sometextbefore", "begin", "sometext", "end", "sometextafter", "begin", "sometext2", "end", "sometextafter2"]
.slice_after(/^end/) # => #<Enumerator: #<Enumerator::Generator:0x007fb1e20b42a8>:each>
.map{ |a| a.shift; a } # => [["begin", "sometext", "end"], ["begin", "sometext2", "end"], []]
ary.pop # => []
ary # => [["begin", "sometext", "end"], ["begin", "sometext2", "end"]]
If you want the resulting sub-arrays joined then that's an easy step:
ary.map{ |a| a.join("\n") } # => ["begin\nsometext\nend", "begin\nsometext2\nend"]
I'd like to replace/duplicate a substring, between two delimeters -- e.g.,:
"This is (the string) I want to replace"
I'd like to strip out everything between the characters ( and ), and set that substr to a variable -- is there a built in function to do this?
I would just do:
my_string = "This is (the string) I want to replace"
p my_string.split(/[()]/) #=> ["This is ", "the string", " I want to replace"]
p my_string.split(/[()]/)[1] #=> "the string"
Here are two more ways to do it:
/\((?<inside_parenthesis>.*?)\)/ =~ my_string
p inside_parenthesis #=> "the string"
my_new_var = my_string[/\((.*?)\)/,1]
p my_new_var #=> "the string"
Edit - Examples to explain the last method:
my_string = 'hello there'
capture = /h(e)(ll)o/
p my_string[capture] #=> "hello"
p my_string[capture, 1] #=> "e"
p my_string[capture, 2] #=> "ll"
var = "This is (the string) I want to replace"[/(?<=\()[^)]*(?=\))/]
var # => "the string"
str = "This is (the string) I want to replace"
str.match(/\((.*)\)/)
some_var = $1 # => "the string"
As I understand, you want to remove or replace a substring as well as set a variable equal to that substring (sans the parentheses). There are many ways to do this, some of which are slight variants of the other answers. Here's another way that also allows for the possibility of multiple substrings within parentheses, picking up from #sawa's comments:
def doit(str, repl)
vars = []
str.gsub(/\(.*?\)/) {|m| vars << m[1..-2]; repl}, vars
end
new_str, vars = doit("This is (the string) I want to replace", '')
new_str # => => "This is I want to replace"
vars # => ["the string"]
new_str, vars = doit("This is (the string) I (really) want (to replace)", '')
new_str # => "This is I want"
vars # => ["the string", "really, "to replace"]
new_str, vars = doit("This (short) string is a () keeper", "hot dang")
new_str # => "This hot dang string is a hot dang keeper"
vars # => ["short", ""]
In the regex, the ? in .*? makes .* "lazy". gsub passes each match m to the block; the block strips the parens and adds it to vars, then returns the replacement string. This regex also works:
/\([^\(]*\)/
I have product codes that look like:
abc123
abcd23423
I need to get all the leading characters before the first instance of a number, so:
abc
abcd
What's the best way to do this?
"abc123 abcd23423".scan(/(\D*)\d+/)
=> [["abc"], [" abcd"]]
"abc123 abcd23423".scan(/(\D*)\d+/).join
=> "abc abcd"
'abc123 abcd23423'.split(/\d+/).join
or just
'abc123 abcd23423'.gsub(/\d+/,'')
DATA.each do |l|
chars = l[/^([[:alpha:]]+)/, 1] # [:alpha:] = [a-zA-Z]
puts chars
end
__END__
abc123
abcd23423
# >> abc
# >> abcd
If you want to capture the alpha into an array do something like this:
ary = []
DATA.each do |l|
ary << l[/^([[:alpha:]]+)/, 1] # [:alpha:] = [a-zA-Z]
end
ary # => ["abc", "abcd"]
__END__
abc123
abcd23423
I didn't use \D because it means all non-numeric (AKA [^0-9]), but that can be dangerous if you are going to run into any other text that is not an alpha character:
'abc_-$%#123'[/^(\D+)/, 1] # => "abc_-$%#"
For the same reason \w is not necessarily safe:
'abc_-$%#123'[/^(\w+)/, 1] # => "abc_"
[[:alpha:]] is the alphabet characters [a-zA-Z]
'abc_-$%#123'[/^([a-zA-Z]+)/, 1] # => "abc"
'abc_-$%#123'[/^([[:alpha:]]+)/, 1] # => "abc"
You can use a regular expression which detects the beginning of the string (\A) and tries to capture as many non-digit characters (\D*) as possible (* is greedy by default):
processed_codes = codes.map { |code| code.scan(/\A(\D*)/)[0] }
You can also use String#match of course, but it has less predictable/intuitive behavior.
I have an array of entries I would like to print.
Being arr the array, I used just to write:
puts arr
Then I needed to use the DOS format end-of-line: \r\n, so I wrote:
arr.each { |e| print "#{e}\r\n" }
This works correctly, but I would like to know if there is a way to specify what end-of-line format to use so that I could write something like:
$eol = "\r\n"
puts arr
UPDATE 1
I know that puts will use the correct line-endings depending on the platform it is run on, but I need this because I will write the output to a file.
UPDATE 2
As Mark suggested, setting $\ is useful. Anyway it just works for print.
For example,
irb(main):001:0> a = [1, 2, 3]
=> [1, 2, 3]
irb(main):002:0> $\ = "\r\n"
=> "\r\n"
irb(main):003:0> print a
123
=> nil
irb(main):004:0> puts a
1
2
3
=> nil
print prints all array items on a single line and then add $\, while I would like the behaviour of puts: adding $\ after each item of the array.
Is this possible at all without using Array#each?
The Ruby variable $\ will set the record separator for calls to print and write:
>> $\ = '!!!'
=> "!!!"
>> print 'hi'
hi!!!=> nil
Alternatively you can refer to $\ as $OUTPUT_RECORD_SEPARATOR if you import the English module.
Kernel#puts is equivalent to STDOUT.puts; and IO.puts "writes a newline after every element that does not already end with a newline sequence". So you're out of luck with pure puts for arrays. However, the $, variable is the separator string output between parameters suck as Kernel#print and Array#join. So if you can handle calling print arr.join, this might be the best solution for what you're doing:
>> [1,2,3].join
=> "123"
>> $, = '---'
=> "---"
>> [1,2,3].join
=> "1---2---3"
>> $\ = '!!!'
=> "!!!"
>> print [1,2,3].join
1---2---3!!!=> nil