ruby string escape when adding - ruby-on-rails

In Ruby on Rails,I got a string number is made of 3 parts : prefix , counter , suffix
In model Setup:
def self.number
prefix = setup.receipt_prefix.blank? ? "" : setup.receipt_prefix.to_s
counter = setup.receipt_counter.blank? ? "" : setup.receipt_counter+1
suffix = setup.receipt_suffix.blank? ? "" : setup.receipt_suffix.to_s
each individual string shows fine:
puts prefix
=> \#_
puts counter
=>
1234
puts suffix
=>
#$#s
but when I add 3 string together, an addition back slash appear :
prefix + counter + suffix
=>
\\#_1234\#$#s
how can I escape "#" "\" when I add 3 string together ? like
=>
\#_1234#$#s
any Ruby or Rails's helper I can use in the model?
thx~~

The string will look different if you get the value versus print (puts) it out. See the following irb session.
>> a = "\\#_"
=> "\\#_"
>> puts a
\#_
=> nil
>> b = "1234"
=> "1234"
>> puts a + b
\#_1234
=> nil
>> a + b
=> "\\#_1234"
The actual string value has two backslashes in it. But only one shows up if you print the string.

Related

Ruby: Get the value if end_with? is true

Looking for a clean way to return the characters of a string if end_with? evaluates to true.
i.e.
s = "my_name"
name = s.end_with?("name")
puts name
>> "name"
My use case would look somewhat like this:
file_name = "some_pdf"
permitted_file_types = %w(image pdf)
file_type = file_name.end_with?(*permitted_file_types)
puts file_type
>> "pdf"
I would do this:
"my_name".scan(/name\z/)[0]
#=> "name"
"something".scan(/name\z/)[0]
#=> nil
May be using match and \z (end of string)?
string = "my_name"
suffix1 = "name"
suffix2 = "name2"
In Ruby >= 3.1
result1 = %r{#{suffix1}\z}.match(string)&.match(0)
# => "name"
result2 = %r{#{suffix2}\z}.match(string)&.match(0)
# => nil
In Ruby < 3.1
result1 = %r{#{suffix1}\z}.match(string)&.[](0)
# => "name"
result2 = %r{#{suffix2}\z}.match(string)&.[](0)
# => nil
Just for fun trick with tap:
string.tap { |s| break s.end_with?(suffix1) ? suffix1 : nil }
# => "name"
string.tap { |s| break s.end_with?(suffix2) ? suffix2 : nil }
# => nil
ruby already has a String#end_with? method, going back to at least version 2.7.1, maybe earlier. But it returns a boolean and you want the matched string to be returned. You're calling a method on an instance of String, so you're apparently wanting to add a method to the String class.
class String #yeah we're monkey patching!
def ends_with?(str) #don't use end_with.. it's already defined
return str if self.end_with?(str)
end
end
#now
s="my_name"
s.ends_with?("name") #=> "name"
But I really wouldn't bother with all that... I'd just work with what Ruby provides:
s = "my_name"
str = "name"
result = str if s.end_with?(str)

How to expand a string in Ruby based on some condition?

I have a string a5bc2cdf3. I want to expand it to aaaaabcbccdfcdfcdf.
In the string is a5, so the resulting string should contain 5 consecutive "a"s, "bc2" results in "bc" appearing 2 times consecutively, and cdf should repeat 3 times.
If input is a5bc2cdf3, and output is aaaaabcbccdfcdfcdf how can I do this in a Ruby method?
def get_character("compressed_string",index)
expanded_string = calculate_expanded_string(compressed_string)
required_char = expanded_string(char_at, index_number(for eg 3))
end
def calculate_expanded_string(compressed_string)
return expanded
end
You may use a regex like
.gsub(/([a-zA-Z]+)(\d+)/){$1*$2.to_i}
See the Ruby online demo
The /([a-zA-Z]+)(\d+)/ will match stubstrings with 1+ letters (([a-zA-Z]+)) and 1+ digits ((\d+)) and will capture them into 2 groups that are later used inside a block to return the string you need.
Note that instead of [a-zA-Z] you might consider using \p{L} that can match any letters.
You want to break out of gsub once the specified index is reached in the original "compressed" string. It is still possible, see this Ruby demo:
s = 'a5bc2cdf3' # input string
index = 5 # break index
result = "" # expanded string
s.gsub!(/([a-zA-Z]+)(\d+)/){ # regex replacement
result << $1*$2.to_i # add to the resulting string
break if Regexp.last_match.end(0) >= index # Break if the current match end index is bigger or equal to index
}
puts result[index] # Show the result
# => b
For brevity, you may replace Regexp.last_match with $~.
I would propose to use scan to move over the compressed string, using a simple RegEx which detects groups of non-decimal characters followed by their count as decimal /([^\d]+)(\d+)/.
def get_character(compressed_string, index)
result = nil
compressed_string.scan(/([^\d]+)(\d+)/).inject(0) do |total_length, (chars, count)|
decoded_string = chars * count.to_i
total_length += decoded_string.length
if index < total_length
result = decoded_string[-(total_length - index)]
break
else
total_length
end
end
result
end
Knowing the current (total) length, one can break out of the loop if the current expanded string includes the requested index. The string is never decoded entirely.
This code gives the following results
get_character("a5bc2cdf3", 5) # => "b"
get_character("a5bc2cdf3", 10) # => "d"
get_character("a5bc2cdf3", 20) # => nil
Just another way. I prefer Wiktor's method by a long way.
def stringy str, index
lets, nums = str.split(/\d+/), str.split(/[a-z]+/)[1..-1].map(&:to_i)
ostr = lets.zip(nums).map { |l,n| l*n }.join
ostr[index]
end
str = 'a5bc2cdf3'
p stringy str, 5 #=> "b"
I'd use:
str = "a5bc2cdf3"
str.split(/(\d+)/).each_slice(2).map { |s, c| s * c.to_i }.join # => "aaaaabcbccdfcdfcdf"
Here's how it breaks down:
str.split(/(\d+)/) # => ["a", "5", "bc", "2", "cdf", "3"]
This works because split will return the value being split on if it's in a regex group: /(\d+)/.
str.split(/(\d+)/).each_slice(2).to_a # => [["a", "5"], ["bc", "2"], ["cdf", "3"]]
The resulting array can be broken into the string to be repeated and its associated count using each_slice(2).
str.split(/(\d+)/).each_slice(2).map { |s, c| s * c.to_i } # => ["aaaaa", "bcbc", "cdfcdfcdf"]
That array of arrays can then be processed in a map that uses String's * to repeat the characters.
And finally join concatenates all the resulting expanded strings back into a single string.

Removing leading and trailing double quotes in string in rails

I want to trim the leading and trailing quotes of a string without any replacement.. I have tried with gsub.. but nothing helped.. I want to achieve something like., "hai" to hai
In Java, I ll use like the following.,
String a="\"hai";
String z=a.replace("\"", "");
System.out.println(z);
Output:
hai
How can I achieve this in rails? Kindly pls help..
In my irb
2.2.3 :008 > str = "\"hai"
=> "\"hai"
2.2.3 :009 > str.tr!('\"', '')
=> "hai"
Why am I not able to get output without double quotes?? Sorry ., If my question doesn't meet your standard..
You can also use .tr method.
str = "\"hai"
str = str.tr('\"', '')
##OR
str.tr!('\"', '')
## OUTPUT
"hai"
You can pass a regex instead, try this
str = "\"hai"
str = str.gsub(/\"/, '')
Hope that helps!
This removes the leading and trailing double quotes from the string only. You get a new string and keep the old one.
str = "\"ha\"i\""
# => "\"ha\"i\""
new_str = str.gsub(/^"+|"+$/, '')
# => "ha\"i"
str
# => "\"ha\"i\""
Or you change the original string.
str.gsub!(/^"+|"+$/, '')
# => "ha\"i"
str
# => "ha\"i"
That's a ruby convention. Method names with an exclamation mark/point modify the object itself.
This should work:
str = "\"hai"
str.tr('"', '')
Note that you only escape (\") double-quotes in a string that is defined using double-quotes ("\""), otherwise, you don't ('"').

Replace with gsub a regexp with accents

I try to get a function for setting < b > around catched strings (case insensitive), like this :
bold_string("Hello everyone","o")
> "Hell<b>o</b> every<b>o</b>ne"
bold_string("HEllo evEryonE", "e")
> "H<b>E</b>llo <b>e</b>v<b>E</b>ryon<b>E<b/>"
Now, my function looks like that :
def bold_string(str, search)
str.gsub(/(#{search})/i, '<b>\1</b>')
end
It works perfectly with the previous examples, but not with the words having some accents. There are the results I expect :
bold_string("Petite bête", "e")
> "P<b>e</b>tit<b>e</b> b<b>ê</b>t<b>e</b>"
bold_string("Petite bête", "ê")
> "P<b>e</b>tit<b>e</b> b<b>ê</b>t<b>e</b>"
In other words, I have to find a regex like /search/i, it says "you have to find the word 'search' or the word 'search' with some accents".
edit :
I see I was too simplist with my example... It should works with string and not simply chars :
bold_string("Petite bête", "êt")
> "P<b>et</b>ite</b> b<b>êt</b>e"
Regards
Pierre
edit2 :
I used the solution of F.J with this new function
def regex_from_string_including_accents(str)
accents = ['aàâ', 'eéèêë', 'oöô' 'iî']
return str.gsub(/./) do |letter|
accent_group = accents.detect{|group| group.include?(letter)}
accent_group ? "[#{accent_group}]" : letter
end
end
You could do something like the following:
def bold_string(str, search)
h = { "e" => "[eéê]", "a" => "[aáâ]" }
regex = search.gsub(/./) {|s| h.fetch(s, s)}
str.gsub(/(#{regex})/i, '<b>\1</b>')
end
Obviously this just shows you how to get started, you will need to fill h with additional accented versions of characters.
Example: http://ideone.com/KukiKc

How do you use variables in regex?

I am trying to pull from this string the photo ID : 30280 :
"--- !ruby/struct:PhotoJob \nimage_id: 30280\n"
I've seen this sort of thing done in regex before where you can look for a couple parameters that match like /nimage_id: \d/ and then return \d.
How can I return /d or the number 30280 from that string?
What's funny is that you have a Ruby Struct there, so you could do the following and let YAML take care of the parsing.
PhotoJob = Struct.new(:image_id)
job = YAML.load("--- !ruby/struct:PhotoJob \nimage_id: 30280\n")
job.image_id
=> 30280
use group matches "--- !ruby/struct:PhotoJob \nimage_id: 30280\n".scan(/image_id: (\d+)/)[0]
>> matches = "--- !ruby/struct:PhotoJob \nimage_id: 30280\n".match(/struct:(.*) .*image_id: (\d+)/m)
=> #<MatchData "struct:PhotoJob \nimage_id: 30280" 1:"PhotoJob" 2:"30280">
>> matches[1]
=> "PhotoJob"
>> matches[2]
=> "30280"
str = "--- !ruby/struct:PhotoJob \nimage_id: 30280\n"
image_id = str.scan(/\d+/)[0]
#=> "30280"
RE = '\nimage_id: (\d+)\n'
The group defined by parentheses around \d+ catches the number

Resources