I tried to create a Morse Decoder. It replaces latin letters with their morse codes. There is one whitespace between letters and three whitespace between words.
def decodeMorse(morseCode)
morse_dict = {
"a" => ".-","b" => "-...","c" => "-.-.","d" => "-..","e" => ".","f" => "..-.","g" => "--.","h" => "....","i" => "..","j" => ".---","k" => "-.-","l" => ".-..","m" => "--","n" => "-.","o" => "---","p" => ".--.","q" => "--.-","r" => ".-.","s" => "...","t" => "-","u" => "..-","v" => "...-","w" => ".--","x" => "-..-","y" => "-.--","z" => "--.."," " => " ","1" => ".----","2" => "..---","3" => "...--","4" => "....-","5" => ".....","6" => "-....","7" => "--...","8" => "---..","9" => "----.","0" => "-----"
}
wordList = morseCode.split(" ")
wordList.each do |word|
word = word.downcase
word.split("").each do |letter|
a = ' ' + morse_dict[letter].to_s + ' '
word.gsub! letter a
end
end
sentence = wordList.join(' ')
return sentence.lstrip
end
puts decodeMorse("Example from description")
Then I got this error:
NoMethodError: undefined method `letter' for main:Object
from codewars.rb:12:in `block (2 levels) in decodeMorse'
from codewars.rb:10:in `each'
from codewars.rb:10:in `block in decodeMorse'
from codewars.rb:8:in `each'
from codewars.rb:8:in `decodeMorse'
What is wrong?
The problem is here:
word.gsub! letter a
it is being interpreted from the right to the left since there is no comma between letter and a it’s being treated as letter(a) function call. You want both letter and a to be passed as parameters to a function call ⇒ separate them with comma:
# ⇓ HERE
word.gsub! letter, a
BTW, gsub might take a hash as a second param to make substitutions:
word.gsub(/./, morse_dict)
would change all letters to their Morse representations. To deal with spaces one might use gsub that takes a block:
word.gsub(/./) { |l| " #{morse_dict[l]} " }.squeeze(' ')
Related
I'm trying to solve a code challenge about Morse Code, the idea is to:
Receive: morse_text = '.... ..|--. ..- -.-- ...'
Return: 'HI GUYS'
But I am getting 'HIGUYS'
where the pipe should be converted into a space between the 2 words. So far I got:
def decode(morse_text)
# TODO: Decode the morse text
morse_text = morse_text.tr("|", " ")
array = morse_text.split(" ").map { |word| encode_word.invert[word].upcase }
array.join
end
def encode_word
morse_code = {
"a" => ".-",
"b" => "-...",
"c" => "-.-.",
"d" => "-..",
"e" => ".",
"f" => "..-.",
"g" => "--.",
"h" => "....",
"i" => "..",
"j" => ".---",
"k" => "-.-",
"l" => ".-..",
"m" => "--",
"n" => "-.",
"o" => "---",
"p" => ".--.",
"q" => "--.-",
"r" => ".-.",
"s" => "...",
"t" => "-",
"u" => "..-",
"v" => "...-",
"w" => ".--",
"x" => "-..-",
"y" => "-.--",
"z" => "--..",
" " => "|"
}
end
I'm struggling in convert the pipe into a blank space so I can get the desire result.
The issue is that you're converting the pipe to a space which means you lose the unique separator for words and treat it as just a standard separator of characters. Instead, split by the pipe and operate on an array of words:
def decode(morse_text)
# Split the morse code into an array of encoded words
encoded_words = morse_text.split('|')
# Decode each word letter by letter
decoded_words = encoded_words.map do |word|
word.split(' ').map { |letter| encode_word.invert[letter].upcase }
end
# Join each decoded word into a string
joined_words = decoded_words.map { |word| word.join }
# Join each word into a single string
decoded_text = joined_words.join(' ')
end
The result is:
decode('.... ..|--. ..- -.-- ...')
=> "HI GUYS"
Simply use the form of String#gsub that employs a hash for making substitutions.
If the variable morse_code holds your hash, with the additional key_value pair ""=>" ", compute the following hash.
decoding_map = morse_code.invert.transform_values(&:upcase)
#=> {".-"=>"A", "-..."=>"B", "-.-."=>"C", "-.."=>"D", "."=>"E",
# ...
# "-..-"=>"X", "-.--"=>"Y", "--.."=>"Z", "|"=>" ", , " "=>""}
Then
morse_text = '.... ..|--. ..- -.-- ...'
morse_text.gsub(/[| ]|[.-]+/, decoding_map)
#=> "HI GUYS"
The regular expression reads, "match a pipe or space or a mix of one or more periods or hyphens".
CSV.foreach("C:/Users/StocksCSV/XOM/XOM.N_BAL_ANN.csv",:col_sep => ';', :skip_blanks => true) do |row|
row.gsub(/[^,]/,"")
#puts row.inspect
ANN_BAL_TBL.insert(:company_name => 'XOM', :statement_title => row[0], :item1 => row[1],
:item2 => row[2], :item3 => row[3], :item4 => row[4], :item5 => row[5])
end
puts "ANN_BAL_TBL DB Row Count: #{ANN_BAL_TBL.count}"
This causes the error:
"undefined method `gsub' for #<Array:0x26d4bc0> (NoMethodError)"
My CSV file is as follows (I just want to remove the "," in the currency)
" In Millions of U.S. Dollars (except for per share items);2012
2012-12-31;2011 2011-12-31 Reclassified 2012-12-31;2010
2010-12-31;2009 2009-12-31;2008 2008-12-31
Cash & Equivalents;9,582.0;12,664.0;7,825.0;10,693.0;31,437.0 "
Try this:
row = row.map { |i| i.gsub(',', '') }
What that'll do is call gsub on every item in the array, and it'll work as long as each item is a string. What you're trying to do is call gsub on an array, which isn't possible.
I have a string like this
a="[\"6000208900\",\"600020890225\",\"600900231930\"]"
#expected result [6000208900,600020890225,600900231930]
I am trying to remove the backslash from the string.
a.gsub!(/^\"|\"?$/, '')
Inside the double quoted string(""), another double quotes must be escaped by \. You can't remove it.
Use puts, you can see it is not there.
a = "[\"6000208902912790\"]"
puts a # => ["6000208902912790"]
Or use JSON
irb(main):001:0> require 'json'
=> true
irb(main):002:0> a = "[\"6000208902912790\"]"
=> "[\"6000208902912790\"]"
irb(main):003:0> b = JSON.parse a
=> ["6000208902912790"]
irb(main):004:0> b
=> ["6000208902912790"]
irb(main):005:0> b.to_s
=> "[\"6000208902912790\"]"
update (as per the last edit of OP)
irb(main):002:0> a = "[\"6000208900\",\"600020890225\",\"600900231930\"]"
=> "[\"6000208900\",\"600020890225\",\"600900231930\"]"
irb(main):006:0> a.scan(/\d+/).map(&:to_i)
=> [6000208900, 600020890225, 600900231930]
irb(main):007:0>
The code a.gsub!(/^\"|\"?$/, '') can't remove the double quote characters because they are not at the beginning and the end of the string. To get what you want try this:
a.gsub(/((?<=^\[)")|("(?=\]$))/, '')
try this:
=> a = "[\"6000208902912790\"]"
=> a.chars.select{ |x| x =~ %r|\d| }.join
=> "6000208902912790"
=> [a.chars.select { |x| x =~ %r|\d| }.join]
=> ["6000208902912790"] # <= array with string
=> [a.chars.select { |x| x =~ %r|\d| }.join].to_s
=> "[\"6000208902912790\"]" # <= come back :)
a="["6000208902912790"]" will return `unexpected tINTEGER`error;
so a="[\"6000208902912790\"]"is used with \ character for double quotes.
As a solution you should try to remove double quotes that will solve the problem.
Do this
a.gsub!(/"/, '')
When the script wants to increment progressbar value it gives me:
C:/Ruby193/lib/ruby/gems/1.9.1/gems/ruby-progressbar-1.4.0/lib/ruby-progressbar/components
/progressable.rb:93:in `<=': comparison of Fixnum with Array failed (ArgumentError)
The Script is shown belove. I ftryed to find solution but no luck. Can Anyone help me with this?
korpusu_id = []
container.divs(:class => "resItem")
.find_all { |div| div.span(:class => "theText", :text => /TestAuto/).exists? }
.each do |korpuss|
id = korpuss.span.parent.parent.attribute_value("id")
id = id[-38..-1]
korpusu_id.push(id)
end
puts ""
puts "Tagad notiek nepieciešamo korpusu dzēšana..."
progress = ProgressBar.create(:title => "Failu dzēšana:", :progress_mark => "|", :format => "%t [%B] %p%%", :total => korpusu_id)
korpusu_id.each do |korp_id|
#b.goto("#{#env}/CorpusMetadataEditor.aspx?id=#{korp_id}")
#b.execute_script("window.confirm = function() {return true}")
delete_poga = #b.link(:id, "ctl00_ContentPlaceHolder1_lnkDeleteCorpora")
if delete_poga.exists?
delete_poga.click
else
puts "Korpuss\n#{#env}/CorpusMetadataEditor.aspx?id=#{korp_id}\nlietotājam #{lietotajs} nav pieejams rediģēšanai.\nTurpinu ar nākošo korpusu!\n---------------------------------------------"
next
end
container.div(:class => "resItem").wait_until_present
progress.increment
end
I found the final solution for my problem. I changed:
progress = ProgressBar.create(:title => "Failu dzēšana:", :progress_mark => "|", :format => "%t [%B] %p%%", :total => korpusu_id.length)
and this worked for me.
Sorry for spam...
I have an Excel column containing part numbers. Here is a sample
As you can see, it can be many different datatypes: Float, Int, and String. I am using roo gem to read the file. The problem is that roo interprets integer cells as Float, adding a trailing zero to them (16431 => 16431.0). I want to trim this trailing zero. I cannot use to_i because it will trim all the trailing numbers of the cells that require a decimal in them (the first row in the above example) and will cut everything after a string char in the String rows (the last row in the above example).
Currently, I have a a method that checks the last two characters of the cell and trims them if they are ".0"
def trim(row)
if row[0].to_s[-2..-1] == ".0"
row[0] = row[0].to_s[0..-3]
end
end
This works, but it feels terrible and hacky. What is the proper way of getting my Excel file contents into a Ruby data structure?
def trim num
i, f = num.to_i, num.to_f
i == f ? i : f
end
trim(2.5) # => 2.5
trim(23) # => 23
or, from string:
def convert x
Float(x)
i, f = x.to_i, x.to_f
i == f ? i : f
rescue ArgumentError
x
end
convert("fjf") # => "fjf"
convert("2.5") # => 2.5
convert("23") # => 23
convert("2.0") # => 2
convert("1.00") # => 1
convert("1.10") # => 1.1
For those using Rails, ActionView has the number_with_precision method that takes a strip_insignificant_zeros: true argument to handle this.
number_with_precision(13.00, precision: 2, strip_insignificant_zeros: true)
# => 13
number_with_precision(13.25, precision: 2, strip_insignificant_zeros: true)
# => 13.25
See the number_with_precision documentation for more information.
This should cover your needs in most cases: some_value.gsub(/(\.)0+$/, '').
It trims all trailing zeroes and a decimal point followed only by zeroes. Otherwise, it leaves the string alone.
It's also very performant, as it is entirely string-based, requiring no floating point or integer conversions, assuming your input value is already a string:
Loading development environment (Rails 3.2.19)
irb(main):001:0> '123.0'.gsub(/(\.)0+$/, '')
=> "123"
irb(main):002:0> '123.000'.gsub(/(\.)0+$/, '')
=> "123"
irb(main):003:0> '123.560'.gsub(/(\.)0+$/, '')
=> "123.560"
irb(main):004:0> '123.'.gsub(/(\.)0+$/, '')
=> "123."
irb(main):005:0> '123'.gsub(/(\.)0+$/, '')
=> "123"
irb(main):006:0> '100'.gsub(/(\.)0+$/, '')
=> "100"
irb(main):007:0> '127.0.0.1'.gsub(/(\.)0+$/, '')
=> "127.0.0.1"
irb(main):008:0> '123xzy45'.gsub(/(\.)0+$/, '')
=> "123xzy45"
irb(main):009:0> '123xzy45.0'.gsub(/(\.)0+$/, '')
=> "123xzy45"
irb(main):010:0> 'Bobby McGee'.gsub(/(\.)0+$/, '')
=> "Bobby McGee"
irb(main):011:0>
Numeric values are returned as type :float
def convert_cell(cell)
if cell.is_a?(Float)
i = cell.to_i
cell == i.to_f ? i : cell
else
cell
end
end
convert_cell("foobar") # => "foobar"
convert_cell(123) # => 123
convert_cell(123.4) # => 123.4