Ruby gsub problem when using backreference and hashes
String#gsub!
has two forms, one in which you pass in a string as the second argument, in which variable references like $1
and $2
are replaced by the corresponding subexpression match, and one in which you pass in a block, which is called with arguments which have the subexpression matches passed in. You are using the block form when calling gsub!
, but the string in your hash is attempting to use the form in which a string is passed in.
Furthermore, the variable interpolation in your string is occurring before the match; variable interpolation happens as soon as the string is evaluated, which is at the time your hash is being constructed, while for this to work you would need variable interpolation to happen after the subexpression replacement happens (which is never the case; variable interpolation will happen first, and the resulting string would be passed in to gsub!
for gsub!
to substitute the subexpression match for $1
, but $1
would have already been evaluated and no longer in the string, as the interpolation has already occurred).
Now, how to fix this? Well, you probably want to store your blocks directly in the hash (so that the strings won't be interpreted while constructing the hash, but instead when gsub!
invokes the block), with an argument corresponding to the match, and $1
, $2
, etc. bound to the appropriate subexpression matches. In order to turn a block into a value that can be stored and later retrieved, you need to add lambda
to it; then you can pass it in as a block again by prefixing it with &
:
hash = {
/(\d+) years/ => lambda { "#{$1.to_f*2} days" },
/cannot/ => lambda { 'of course we CAN' }
}
hash.each {|k,v|
a.gsub!(k, &v)
}
How to access Hash Map inside string using backreference
You can use a block, then the global variables $1
.. $9
hold matches. This achieves what you want:
map = { 'stack' => 'overflow' }
p "stackoverflow".gsub(/(stack)(overflow)/) { map[$1] + $2 }
# => overflowoverflow
Alternatively, you can just pass a variable to the block:
map = { 'stack' => 'overflow' }
p "stackoverflow".gsub(/stack/) { |match| map[match] }
# => overflowoverflow
See String#gsub for reference.
Using Ruby's gsub with a string containing \0
Escape it with another backslash so that gsub
will know you want "\\0"
.
"replace me".gsub(/replace me/, "this \\\\0 is a test")
(Edit) if by "\0"
you meant the byte 0x00
, do this:
"replace me".gsub(/replace me/, "this \0 is a test")
Ruby 1.9 regex as a hash key
It will not work without some extra code, as it is you are comparing a Regexp object with either an Integer or a String object. They won't be value equal, nor identity equal. They would match but that requires changes to the Hash class code.
irb(main):001:0> /(\d+)/.class
=> Regexp
irb(main):002:0> 2222.class
=> Fixnum
irb(main):003:0> '2222'.class
=> String
irb(main):004:0> /(\d+)/==2222
=> false
irb(main):007:0> /(\d+)/=='2222'
=> false
irb(main):009:0> /(\d+)/.equal?'2222'
=> false
irb(main):010:0> /(\d+)/.equal?2222
=> false
you would have to iterate the hash and use =~ in something like:
hash.each do |k,v|
unless (k=~whatever.to_s).nil?
puts v
end
end
or change the Hash class to try =~ in addition to the normal matching conditions. (I think that last option would be difficult, in mri the Hash class seems to have a lot of C code)
Regex can this be achieved
You will need to use some sort of logic.
str += ',location_manager' unless str.gsub!(/location_manager,/,'')
I'm assuming that if it's not present you append it to the end of the string
How do I write a regular expression that will match characters in any order?
Here is your solution
^(?:([act])(?!.*\1)){3}$
See it here on Regexr
^ # matches the start of the string
(?: # open a non capturing group
([act]) # The characters that are allowed and a capturing group
(?!.*\1) # That character is matched only if it does not occur once more, Lookahead assertion
){3} # Defines the amount of characters
$
The only special think is the lookahead assertion, to ensure the character is not repeated.
^
and $
are anchors to match the start and the end of the string.
How to elegantly symbolize_keys for a 'nested' hash
There are a few ways to do this
There's a
deep_symbolize_keys
method in Railshash.deep_symbolize_keys!
As mentioned by @chrisgeeq, there is a
deep_transform_keys
method that's available from Rails 4.hash.deep_transform_keys(&:to_sym)
There is also a bang
!
version to replace the existing object.There is another method called
with_indifferent_access
. This allows you to access a hash with either a string or a symbol like howparams
are in the controller. This method doesn't have a bang counterpart.hash = hash.with_indifferent_access
The last one is using
JSON.parse
. I personally don't like this because you're doing 2 transformations - hash to json then json to hash.JSON.parse(JSON[h], symbolize_names: true)
UPDATE:
16/01/19 - add more options and note deprecation of deep_symbolize_keys
19/04/12 - remove deprecated note. only the implementation used in the method is deprecated, not the method itself.
Why do dict and lru_cache treat keys that all hash to 0 differently?
Dictionaries don't only use the hash to determine if elements are distinct, they are also checked for equality.
Duplicate elements are elements which are equal, as determined by __eq__
. The behavior you see can be explained by the fact that 0 == ""
returns False
.
>>> 0 == 0.0
True
>>> 0 == 0j
True
>>> 0 == False
True
>>> 0 == ""
False
Related Topics
Ruby Facebook Graph API Appsecret_Proof
Ruby Multiple Background Threads
Ruby 1.8: Hash#Sort Not Return Hash But Array (Better Way to Do This)
How to Dry Up Method with Multiple { 'Not Found' }
How to Dynamically Create Instance Methods at Runtime
Ruby Range: Operators in Case Statement
Validating Phone Number in Ruby
How to Sort an Alphanumeric Array in Ruby
Ruby Sequel: Array Returned by Query Is Being Returned as a String Object, Not an Array Object
Reading Parameters on Sinatra Post
Rational - Original Numbers in Ruby
Initialize the Delayed Jobs Gem by Starting the Workers on Application Start
Where Are Catch and Throw Useful in Ruby