I was reading Why's poignant guide to ruby and came upon this module on chapter 5:
require 'endertromb'
module WishScanner
def scan_for_a_wish
wish = self.read.detect do |thought|
thought.index( 'wish: ' ) == 0
end
wish.gsub( 'wish: ', '' )
end
end
I have been trying to figure out how it works but what is confusing me is how thought.index( 'wish: ' ) == 0 and wish.gsub( 'wish: ', '' ) work. According to the author the purpose of this method is to "only pick up a wish if it starts with the word wish and a colon and a space. That way the planet doesn’t fill up with every less-than-ten-letter word that appears in people’s heads.”
But the way I understand it, thought.index( 'wish: ' ) == 0 will check if thought starts with 'wish: '. However i dont understand wish.gsub( 'wish: ', '' ) in the way I see it it seems to just substitute wish with an empty string.
Can any one offer any explanation or further insight into it?
Thank you in advance for any help.
wish.gsub( 'wish: ', '' ) in the way I see it it seems to just substitute wish with an empty string
Exactly! It replaces the string "wish: " in a string like "wish: A pony!" with "".
I.e. it turns "wish: A pony!" into "A pony!".
Related
I'm currently trying to correct a code for a class and I when I try to the run the module it keeps saying invalid syntax. Please Help!
This is the code.
print (myName + ',thank you for taking this quiz. Your score was ' + myScore 'out of 3. ')
myName = "Jay"
myScore = 1
print ('%s thank you for taking this quiz. Your score was out %d of 3. ') %(myName, myScore)
This is a better way do it. The reason your code doesn't work is because you are missing a '+' after myScore.
print (myName + ',thank you for taking this quiz. Your score was ' + myScore + 'out of 3. ')
That is the corrected version.
Think deeper, your thought should think what syntax error you just made, not focus on a missing of a '+'
I want to insert data into a string via interpolation. I want to check if #call.transferred_from is nil, and if so, output #call.transfer_from_other; else output #call.transferred_from.try(:facility_name) along with #call.transferred_from.try(:facility_address).
Here is my code example:
"#{if #call.transferred_from.nil? #call.transfer_from_other else #call.transferred_from.try(:facility_name) #call.transferred_from.try(:facility_address) end}"
Doing this gives me the following error:
syntax error, unexpected keyword_else, expecting keyword_then or ';' or '\n'
I'm not sure where to go. Any help would be appreciated.
Update: 08/04/14
I moved the conditional into a private controller method as follows:
def transfer_from_address
if #call.transferred_from.nil?
#call.transfer_from_other
else
#call.transferred_from.try(:facility_name) + ' ' + #call.transferred_from.try(:facility_address)
end
end
Then I call the following using string interpolation.
#{transfer_from_address}
This seems to work, but I'm not sure that it's proper Ruby.
I know this is not really answering your question, but I'd caution about putting this much logic in an interpolation. While its totally doable, it makes your code very hard to understand.
The fundamental issue I see with your particular issue is you're trying to return 2 things somehow, yet you're just putting both of them next to eachother which is not valid ruby.
Assuming this is in an interpolation you'd want to somehow return them together ..
#{
#call.transferred_from.nil? ?
#call.transfer_from_other :
#call.transferred_from.try(:facility_name) + ' ' + #call.transferred_from.try(:facility_address)
}
I'd really suggest you move this into a variable or a method tho .. and just reference it in the interpolation.
This could look something like:
facility_name_and_address = #call.transferred_from.nil? ? #call.transfer_from_other : #call.transferred_from.try(:facility_name) + ' ' + #call.transferred_from.try(:facility_address)
{
:body => facility_name_and_address
}
If I understand what you are trying to do, I would suggest adding a method to #call which does the job:
class Call
def transfer_text
return transfer_from_other if transferred_from.nil?
"#{transferred_from.try(:facility_name)} #{transferred_from.try(:facility_address)}"
end
end
Then simply calling #call.transfer_text should provide the needed text.
If you want to be more sophisticated, and you don't want trailing white-space in case facility_name or facility_address are nil, you can create a list of them, and join them with white space:
[transferred_from.try(:facility_name), transferred_from.try(:facility_address)].compact.join(' ')
This will make sure spaces will be only between to non-nil elements. If both are nil, and empty string will be the result (rather than a space), and if one is nil, it won't have a leading/trailing space.
why not using
:body => "#{#call.transferred_from.nil? ? #call.transfer_from_other : #call.transferred_from.try(:facility_name) #call.transferred_from.try(:facility_address)"
but anyway I would not use this compact syntax for better maintainability
You just need to put either a semicolon or then right after the condition.
if #call.transferred_from.nil?; #call.transfer_from_other ...
But in your case, there is not much point in putting the entire condition inside a string interpolation. It is better to do the condition outside the string.
By the way, if you fix your first error, then you might encounter the next error:
#call.transferred_from.try(:facility_name) #call.transferred_from.try(:facility_address)
To fix that as well, I think you should do
#call.transferred_from.instance_eval{|e| e.nil? ?
#call.transfer_from_other.to_s :
"#{e.try(:facility_name)} #{e.try(:facility_address)}"
}
This question already has answers here:
Match a string against multiple patterns
(2 answers)
Closed 8 years ago.
I'm new to ruby and I'm trying to solve a problem.
I'm parsing through several text field where I want to remove the header which has different values. It works fine when the header always is the same:
variable = variable.gsub(/(^Header_1:$)/, '')
But when I put in several arguments it doesn't work:
variable = variable.gsub(/(^Header_1$)/ || /(^Header_2$)/ || /(^Header_3$)/ || /(^Header_4$)/ || /^:$/, '')
You can use Regexp.union:
regex = Regexp.union(
/^Header_1/,
/^Header_2/,
/^Header_3/,
/^Header_4/,
/^:$/
)
variable.gsub(regex, '')
Please note that ^something$ will not work on strings containing something more than something :)
Cause ^ is for matching beginning of string and $ is for end of string.
So i intentionally removed $.
Also you do not need brackets when you only need to remove the matched string.
You can also use it like this:
headers = %w[Header_1 Header_2 Header_3]
regex = Regexp.union(*headers.map{|s| /^#{s}/}, /^\:$/, /etc/)
variable.gsub(regex, '')
And of course you can remove headers without explicitly define them.
Most likely there are a white space after headers?
If so, you can do it as simple as:
variable = "Header_1 something else"
puts variable.gsub(/(^Header[^\s]*)?(.*)/, '\2')
#=> something else
variable = "Header_BLAH something else"
puts variable.gsub(/(^Header[^\s]*)?(.*)/, '\2')
#=> something else
Just use a proper regexp:
variable.gsub(/^(Header_1|Header_2|Header_3|Header_4|:)$/, '')
If the header is always the same format of Header_n, where n is some integer value, then you can simplify your regex greatly:
/Header_\d+/
will find every one of these:
%w[Header_1 Header_2 Header_3].grep(/Header_\d+/)
[
[0] "Header_1",
[1] "Header_2",
[2] "Header_3"
]
Tweaking it to handle finding words, not substrings:
/^Header_\d+$/
or:
/\bHeader_\d+\b/
As mentioned, using Regexp.union is a good start, but, used blindly, can result in very slow or inefficient patterns, so think ahead and help out the engine by giving it useful sub-patterns to work with:
values = %w[foo bar]
/Header_(?:\d+|#{ values.join('|') })/
=> /Header_(?:\d+|foo|bar)/
Unfortunately, Ruby doesn't have the equivalent to Perl's Regexp::Assemble module, which can build highly optimized patterns from big lists of words. Search here on Stack Overflow for examples of what it can do. For instance:
use Regexp::Assemble;
my #values = ('Header_1', 'Header_2', 'foo', 'bar', 'Header_3');
my $ra = Regexp::Assemble->new;
foreach (#values) {
$ra->add($_);
}
print $ra->re, "\n";
=> (?-xism:(?:Header_[123]|bar|foo))
I am currently doing a bunch of processing on a string using regular expressions with gsub() but I'm chaining them quite heavily which is starting to get messy. Can you help me construct a single regex for the following:
string.gsub(/\.com/,'').gsub(/\./,'').gsub(/&/,'and').gsub(' ','-').gsub("'",'').gsub(",",'').gsub(":",'').gsub("#39;",'').gsub("*",'').gsub("amp;",'')
Basically the above removes the following:
.com
.
,
:
*
switches '&' for 'and'
switches ' ' for '-'
switches ' for ''
Is there an easier way to do this?
You can combine the ones that remove characters:
string.gsub(/\.com|[.,:*]/,'')
The pipe | means "or". The right side of the or is a character class; it means "one of these characters".
A translation table is more scalable as you add more options:
translations = Hash.new
translations['.com'] = ''
translations['&'] = 'and'
...
translations.each{ |from, to| string.gsub from, to }
Building on Tim's answer:
You can pass a block to String.gsub, so you could combine them all, if you wanted:
string.gsub(/\.com|[.,:*& ']/) do |sub|
case(sub)
when '&'
'and'
when ' '
'-'
else
''
end
end
Or, building off echoback's answer, you could use a translation hash in the block (you may need to call translations.default = '' to get this working):
string.gsub(/\.com|[.,:*& ']/) {|sub| translations[sub]}
The biggest perk of using a block is only having one call to gsub (not the fastest function ever).
Hope this helps!
I am trying to write a method that is the same as mysqli_real_escape_string in PHP. It takes a string and escapes any 'dangerous' characters. I have looked for a method that will do this for me but I cannot find one. So I am trying to write one on my own.
This is what I have so far (I tested the pattern at Rubular.com and it worked):
# Finds the following characters and escapes them by preceding them with a backslash. Characters: ' " . * / \ -
def escape_characters_in_string(string)
pattern = %r{ (\'|\"|\.|\*|\/|\-|\\) }
string.gsub(pattern, '\\\0') # <-- Trying to take the currently found match and add a \ before it I have no idea how to do that).
end
And I am using start_string as the string I want to change, and correct_string as what I want start_string to turn into:
start_string = %("My" 'name' *is* -john- .doe. /ok?/ C:\\Drive)
correct_string = %(\"My\" \'name\' \*is\* \-john\- \.doe\. \/ok?\/ C:\\\\Drive)
Can somebody try and help me determine why I am not getting my desired output (correct_string) or tell me where I can find a method that does this, or even better tell me both? Thanks a lot!
Your pattern isn't defined correctly in your example. This is as close as I can get to your desired output.
Output
"\\\"My\\\" \\'name\\' \\*is\\* \\-john\\- \\.doe\\. \\/ok?\\/ C:\\\\Drive"
It's going to take some tweaking on your part to get it 100% but at least you can see your pattern in action now.
def self.escape_characters_in_string(string)
pattern = /(\'|\"|\.|\*|\/|\-|\\)/
string.gsub(pattern){|match|"\\" + match} # <-- Trying to take the currently found match and add a \ before it I have no idea how to do that).
end
I have changed above function like this:
def self.escape_characters_in_string(string)
pattern = /(\'|\"|\.|\*|\/|\-|\\|\)|\$|\+|\(|\^|\?|\!|\~|\`)/
string.gsub(pattern){|match|"\\" + match}
end
This is working great for regex
This should get you started:
print %("'*-.).gsub(/["'*.-]/){ |s| '\\' + s }
\"\'\*\-\.
Take a look at the ActiveRecord sanitization methods: http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-c-sanitize_sql_array
Take a look at escape_string / quote method in Mysql class here