Ignoring case for part of regular expression - ruby-on-rails

Is there an easy way to ignore case for part of a regular expression? I'm using Ruby 1.9.3 and Rails 3.2.8 (not sure if Rails helps at all, but thought I'd mention it).
For example, I want to check if a string is "Hello, my name is Bartholomew", but I only care that Bartholomew has proper capitalization. I could do:
/^[Hh][Ee][Ll][Ll][Oo], [Mm][Yy] [Nn][Aa][Mm][Ee] [Ii][Ss] Bartholomew$/
But that's such a pain. I know that I can ignore case for the whole string with /i at the end:
/^hello, my name is bartholomew$/i
But I can't split the string (the regular expression and the string itself are both entered by users).

Here's one way to do it, by making the regex case-sensitive by default and marking the insensitive section:
> pattern = /(?i:hello, my name is) Bartholomew/
=> /(?i:hello, my name is) Bartholomew/
> pattern =~ 'Hello, my Name is Bartholomew'
=> 0
> pattern =~ 'Hello, my Name is bartholomew'
=> nil
The other way to do it is to make the regex case-insensitive by default, and marking the sensitive section:
> pattern = /hello, my name is (?-i:Bartholomew)/i
=> /hello, my name is (?-i:Bartholomew)/i
> pattern =~ 'Hello, my Name is Bartholomew'
=> 0
> pattern =~ 'Hello, my Name is bartholomew'
=> nil

Related

Single Backslash in Ruby String

I am using ruby 2.7.5. I am trying to get ^~\& assigned to a variable. I want string with only one backslash on it. I tried different things but none of them give me the desired result.
attempt normal string
irb(main):049:0> "^~\&"
=> "^~&"
thinking one \ is escaped
irb(main):050:0> "^~\\&"
=> "^~\\&"
thinking string literal will do
irb(main):052:0> '^~\&'
=> "^~\\&"
thinking one \ is skiped on literal
irb(main):053:0> '^~\\&'
=> "^~\\&"
trying how 3 backward slashes will look
irb(main):054:0> '^~\\\&'
=> "^~\\\\&"
some more attempts on how backslash works, it seems like we only get even number of back slashes
irb(main):056:0> "^~\\\&"
=> "^~\\&"
irb(main):057:0> "^~\\\\&"
=> "^~\\\\&"
irb(main):058:0> "^~\\\\\&"
=> "^~\\\\&"
same thing when we use single quote
irb(main):061:0> '^~\\&'
=> "^~\\&"
irb(main):062:0> '^~\\\&'
=> "^~\\\\&"
irb(main):063:0> '^~\\\\&'
=> "^~\\\\&"
I also looked Backslashes in single quoted strings vs. double quoted strings
as per the StackOverflow suggested, I tried their example but the results were not similar.
irb(main):055:0> 'escape using "\\"'
=> "escape using \"\\\""
so could you please help me with how can I get a string with only one backslash? Also, am I missing any string concepts?
You've already done it correctly in your 2nd and 3rd examples. The problem is you're not checking the result properly.
You're relying on the console output of your string definition which gives you an escaped string back. (It essentially runs #inspect on the value, which includes/adds the escape characters.)
To see the true result (without the escaping), use #puts.
puts('^~\&')
^~\&
=> nil
puts("^~\\&")
^~\&
=> nil
Use two backslashes inside single-quoted or double-quoted strings. For example:
ruby -e "s = '^~\\&'; puts s;"
^~\&
ruby -e 's = "^~\\&"; puts s;'
^~\&

Scala Parser, set reserved words

I am writing a simple proggramming language with scala parser. So far no trouble, but im worrying about the relation function name / variable name against reserved words.
I'va already addded some special functions like "floor" ~ gexp or "top" ~ gexp and i dont want anybody using this language being able to name a function or a variable like them. I have not found yet a way to check this.
in Ruby i would write something like
rule varname
lowerid &{ |id| id[0].is_not_reserved } <VarNameNode>
but i dont know how would i write this in scala
def varName : Parser[StringValue] = lowerid
You can use the ^? operator:
def varName: Parser[StringValue] = lowerid ^? ({
case id if !isReserved(id) => id
}, { id => s"Error: $id is reserved." })

Regex in Ruby: expression not found

I'm having trouble with a regex in Ruby (on Rails). I'm relatively new to this.
The test string is:
http://www.xyz.com/017010830343?$ProdLarge$
I am trying to remove "$ProdLarge$". In other words, the $ signs and anything between.
My regular expression is:
\$\w+\$
Rubular says my expression is ok. http://rubular.com/r/NDDQxKVraK
But when I run my code, the app says it isn't finding a match. Code below:
some_array.each do |x|
logger.debug "scan #{x.scan('\$\w+\$')}"
logger.debug "String? #{x.instance_of?(String)}"
x.gsub!('\$\w+\$','scl=1')
...
My logger debug line shows a result of "[]". String is confirmed as being true. And the gsub line has no effect.
What do I need to correct?
Use /regex/ instead of 'regex':
> "http://www.xyz.com/017010830343?$ProdLarge$".gsub(/\$\w+\$/, 'scl=1')
=> "http://www.xyz.com/017010830343?scl=1"
Don't use a regex for this task, use a tool designed for it, URI. To remove the query:
require 'uri'
url = URI.parse('http://www.xyz.com/017010830343?$ProdLarge$')
url.query = nil
puts url.to_s
=> http://www.xyz.com/017010830343
To change to a different query use this instead of url.query = nil:
url.query = 'scl=1'
puts url.to_s
=> http://www.xyz.com/017010830343?scl=1
URI will automatically encode values if necessary, saving you the trouble. If you need even more URL management power, look at Addressable::URI.

Translation in .yml with optional parameter

I want to make a translation my_translation with an optional parameter. For example:
> I18n.t('my_translation')
=> "This is my translation"
> I18n.t('my_translation', parameter: 1)
=> "This is my translation with an optional parameter which value is 1"
Is this possible?
Yes, definitely. You just write the translations like this:
my_translation: This is my translation with an optional parameter which value is %{parameter}
Is the parameter really optional? In above translation, you have to provide all parameters.
UPDATE: Sorry, I answered too soon. I don't think it's easy to do. Maybe the easiest way is like this:
> I18n.t('my_translation1')
=> "This is my translation"
> I18n.t('my_translation2', parameter: 1)
=> "This is my translation with an optional parameter which value is 1"
I would say it is possible, though not recommended. You have two completely separate strings, based on your comments in #Yanhao's answer, and I would say they should be two separate entries in your yaml file:
report_name: My report
report_name_with_date: My report on %{date}
Since the existence of the date determines which string to display, you could perhaps test for its existence in in the params hash in a controller method, assign the title to a variable, and then use it in a view. Perhaps something like:
report_date = params[:report_date]
if report_date && report_date.is_a?(Date)
#report_name = I18n.t('report_name_with_date', date: report_date.to_s)
else
#report_name = I18n.t('report_name')
end
If you want behaviour exactly as you have described, you'd need two yaml entries anyway, and you'd have extra convolution, and you'd be doing a I18n no-no by creating a string by concatenating two strings together, which assumes a fixed grammatical sentence structure (not to mention this drives translators up the wall):
report_name_with_date: My report%{on_date}
on_date: on %{date}
with code something like this:
report_date = params[:report_date]
if report_date && report_date.is_a?(Date)
on_date = I18n.t('on_date', date: report_date.to_s)
#report_name = I18n.t('report_name_with_date', on_date: " #{on_date}")
else
#report_name = I18n.t('report_name_with_date', on_date: nil)
end
So, in summary, I'd say go with two separate whole strings, like in the first example.
This is the way i did it!
First set my translation
I18n.t('my_translation', parameter: optional_parameter)
Check if value is nil
optional_parameter = value.nil? "" : "with an optional parameter which value is #{value}"
I18n.t('my_translation', parameter: optional_parameter)
if value is nil =>"This is my translation"
if value is 1 => "This is my translation with an optional parameter which value is 1"
If you're using a number as an optional argument, Rails provides a better way to handle it.
e.g.
invoice:
zero: "Great! You have no pending invoices."
one: "You have only 1 pending invoice."
other: "You have %{count} pending invoices."
>> t("invoice", count: 0)
=> Great! You have no pending invoices.
>> t("invoice", count: 1)
=> You have only 1 pending invoice.
>> t("invoice", count: 5)
=> You have 5 pending invoices.

Please explain this code from watchr

I'm learning to use watchr, a ruby gem that watches files and runs something if they change
watch( 'test/test_.*\.rb' ) {|md| system("ruby #{md[0]}") }
watch( 'lib/(.*)\.rb' ) {|md| system("ruby test/test_#{md[1]}.rb") }
Specifically, I don't understand what md[0] and md[1] are. I know that 'test/tests_.*\.rb' is a regular expression and it's retrieving a list of files. I also know that |md| represents filenames that match the regular expression. But I'm not sure what md[0] and md[1] would point to
I suspect that md is a MatchData instance, where [0] it the entire matched text and [1] is the first captured sub-expression), in this case the filename inside the lib directory, without the extension.
Ruby's regular expression operator (=~) returns an object that responds to :[]. The values 0 and 1 refer to the matched string and the first group (the part in the parentheses).
So for example if the strings being tested were:
"test/test_sample.rb"
"lib/sample.rb"
Then the first expression (/test/test_.*.rb/) would match "test/test_sample.rb", and the second expression (/lib/(.*).rb/) would match "sample". You can see this in the console:
> /test\/test_.*\.rb/ =~ "test/test_sample.rb"
# => 0
> $~[0]
# => "test/test_sample.rb"
> /lib\/(.*)\.rb/ =~ "lib/sample.rb"
# => 0
> $~[0]
# => "lib/sample.rb"
> $~[1]
# => "sample"
md stands for MatchData, which is the class of the object Ruby uses to return the result of the regex match.
zetetic's answer is correct; md is an instance of Rudy's MatchData class, which is the result of applying the regular expression on the modified file (see String#match).
The relevant line from the Watchr source code is at: https://github.com/mynyml/watchr/blob/17fa9bf80998483f9cf69a934bbcb726a0c389fa/lib/watchr/script.rb#L204

Resources