comparison of string with nil failed - ruby

Im trying to write a loop that counts the number of capitals in a word. When I run this code I get an error stating that nil can't be compared to a string. I don't understand this because I am comparing a a string to a string?
passwort = gets.chomp
i = 0
capitals = 0
while(i < (passw0ort.length) + 1) do
if('A' <= passwort[i] && passwort[i] <= 'Z')
capitals = capitals + 1
else
end
i = i + 1
end
Greetings Patrick

The reason why you are getting nil is that you are counting more elements than there are.
i<(passw0ort.length)+1 should be i<(passw0ort.length), because .length returns a number bigger than zero, if the string is not empty, while arrays are zero-indexed. The last time the loop runs, you try to access an element after the string, which does not exist.
So on your last loop iteration, you are comparing a string to nil, which results in this error.

Just use scan method of String class to filter out only capital letters
capitals = passwort.scan(/[A-Z]/).count

Your loop is too "long":
passwort = "test"
i = 0
while i < passwort.length + 1
puts "passwort[#{i}] == #{passwort[i].inspect}"
i = i + 1
end
Output:
passwort[0] == "t"
passwort[1] == "e"
passwort[2] == "s"
passwort[3] == "t"
passwort[4] == nil # <- this is your nil error
You can fix this by changing i < passwort.length + 1 to i < passwort.length.
However, instead of using temporary variables and while loops, you can use String#chars to get the string's characters as an array and Array#count to count the ones satisfying your condition:
passwort = "123fooBAR"
passwort.chars.count { |char| 'A' <= char && char <= 'Z' }
#=> 3
Or simply String#count:
passwort.count("A-Z") #=> 3
From the docs:
The sequence c1-c2 means all characters between c1 and c2.

Related

While loop through a string in Ruby

I am entering "901000" as an argument to the following method, and I expect it to remove the last three zeros and return "901".
def zeros(x)
str = x.to_s
i = str.length-1
while str[i] == "0"
str = str.delete(str[i])
i = i-1
end
return str
end
But it returns "91" instead. I cannot understand why my code does not work. Can someone help please?
At first, str is "901000", i = str.length-1 is 5, and str[i] is "0". Hence,
str = str.delete(str[i])
is equivalent to
str = "901000".delete("0")
That gives you "91".
Then, by i = i-1, i becomes 4, and str[i] (which is equivalent to "91"[4]) becomes nil, and str[i] == 0 (which is equivalent to nil == 0) becomes false. So the loop ends, returning the value str, which is "91".
To do what you want, some simple ways are:
"901000".sub(/0+\z/, "") # => "901"
"901000"[/.*?(?=0+\z)/] # => "901"

why does this ruby code not return anything?

I'm trying to take a number and return a string with dashes around any odd numbers. Also, the string should not begin or end with a dash.
I've written the following but it does not return anything:
def dasherize_number(num)
string = num.to_s
i = 0
while i<string.length
if (string[i].to_i % 2) != 0
string[i] = '-' + string[i] + '-'
end
i += 1
end
if string[0] == '-'
string.pop(1)
end
if (string.length - 1) == '-'
string.pop(1)
end
string
end
It appears to be looping infinitely if I understand correctly; the console shows no output and doesn't allow me to do anything else unless I refresh. I've reviewed the code by each character, but I can't figure where it goes wrong.
There were a lot of logical issues in your code.
here's something that might just work for you
def dasherize_number(num)
string = num.to_s
str_len = string.length
i = 0
while i < str_len
next if string[i] == '-'
if (string[i].to_i % 2) != 0
string[i] = '-' + string[i] + '-'
str_len = string.length
i += 3
else
i += 1
end
end
if string[0] == '-'
string = string[1..-1]
end
if (string[string.length - 1]) == '-'
string = string[0..-2]
end
string.gsub('--', '-')
end
Explaination
Firstly, you had this condition in your while loop i < string.length
Which wouldn't work, because the length of the string keeps changing. So i've used a variable to store the value and update the variable if the string is updated.
If the string is updated, we can be sure that we can skip the next two indexes.
eg: number inputed -> 122
then after first iteration the string would be -1-22
so we don't want to run the same condition for the next index because, that would be 1 again, hence the infinite loop. (Hope you get the idea)
pop wouldn't work on string, just because we can access characters using indexes like for arrays, we can't use pop for strings.
To make sure there are no consecutive dashes, i've used gsub to replace them with single dash.
The problem seems to be in this part of the code:
while i<string.length
if (string[i].to_i % 2) != 0
string[i] = '-' + string[i] + '-'
end
i += 1
end
If your string contains odd number it increases its length by 2 more chars (2x-), but incrementing it by 1 (i+=1).
Assign initial string length to a var and check its length in the while loop.
string_length = string.length
while i < string_length
if ((string[i].to_i % 2) != 0)
string[i] = '-' + string[i] + '-'
end
i += 1
end

Code doesn't work in coderbytes but it works in Cloud9

In Cloud9 I use the following code and it works.
def LongestWord(sen)
i = 0
cha ="&#%*^$!~(){}|?<>"
new = ""
while i < sen.length
i2 = 0
ch = false
while i2 < cha.length
if sen[i] == cha[i2]
ch = true
end
i2 += 1
end
if ch == false
new += sen[i].to_s
end
i += 1
end
words = new.split(" ")
longest = ""
idx = 0
count = 0
while idx < words.length
word = words[idx]
if word.length > count
longest = word
count = word.length
end
idx += 1
end
# code goes here
return longest
end
# keep this function call here
# to see how to enter arguments in Ruby scroll down
LongestWord("beautifull word")
In Codebytes in the exercise "Longest Word" you have to use the same STDIN in the arguments. It is the same code but changing the argument but it doesn't work:
def LongestWord(sen)
i = 0
cha ="&#%*^$!~(){}|?<>"
new = ""
while i < sen.length
i2 = 0
ch = false
while i2 < cha.length
if sen[i] == cha[i2]
ch = true
end
i2 += 1
end
if ch == false
new += sen[i].to_s
end
i += 1
end
words = new.split(" ")
longest = ""
idx = 0
count = 0
while idx < words.length
word = words[idx]
if word.length > count
longest = word
count = word.length
end
idx += 1
end
# code goes here
return longest
end
# keep this function call here
# to see how to enter arguments in Ruby scroll down
LongestWord(STDIN.gets)
I think may be something is creating some kind of conflict with the browser. The output shows a lot of numbers. Can some one help me testing the code?. Any feedback is appreciated, thanks!
Coderbyte is running your code on an old version of Ruby - Ruby 1.8.7
In this version of Ruby, using an index into a string like sen[i] doesn't return the character at i, it returns the numeric ASCII value of that character instead. That's where the numbers are coming from.
To get the code to work on Ruby 1.8.7 you can replace some_string[i] with some_string[i, 1] - this variation returns the substring of length 1 starting at i so is the same as the behaviour of some_string[i] in more recent Ruby versions. See the docs here for more details.

Ruby longest palindrome - why does a slight modification in a while loop break my code?

I'm trying to solve this Ruby problem and I can't figure out why having a minor while loop difference renders one test false: longest_palindrome("abba") outputs "bb" instead of "abba", which is false. I can only solve it with for and while loops, so please no advanced methods. It's easier to highlight the difference in the code block (first one is the working solution, second is mine. Also assume the palindrome? method is already defined):
def longest_palindrome(string)
best_palindrome = nil
idx1 = 0
***while idx1 < string.length
length = 1
while (idx1 + length) <= string.length
substring = string.slice(idx1, length)***
if palindrome?(substring) && (best_palindrome == nil || substring.length > best_palindrome.length)
best_palindrome = substring
end
length += 1
end
idx1 += 1
end
return best_palindrome
end
def longest_palindrome(string)
longest = nil
i = 0
***while i < string.length
i2 = 1
while i2 < string.length***
if palindrome?(string.slice(i, i2)) == true && (longest == nil || string.slice(i, i2).length > longest.length)
longest = string.slice(i, i2)
end
i2 += 1
end
i += 1
end
return longest
end
This part of your code...
while i2 < string.length
... means you're never checking the maximum possible length.
"abba".slice(0,4) is the entire string, but you only ever go up to "abba".slice(0,3) which is "abb".
So you never test the entire string.
Change the line to...
while i2 <= string.length
...and it should be ok.

Why doesn't my conversion code for roman numbers ('mcmxcix' for e.g) to real numbers work?

I want to convert Roman numerals, such as "mcmxcix", to arabic integers like "1999".
My code looks like:
#~ I = 1 V = 5 X = 10 L = 50
#~ C = 100 D = 500 M = 1000
def roman_to_integer roman
len = roman.length
x = 1
while x <= len
arr = Array.new
arr.push roman[x]
x += 1
end
num = 0
arr.each do |i|
if i == 'I'
num += 1
elsif i == 'V'
num += 5
elsif i == 'X'
num += 10
elsif i == 'L'
num += 50
elsif i == 'C'
num += 100
elsif i == 'D'
num += 500
elsif i == 'M'
num += 1000
end
end
num
end
puts(roman_to_integer('MCMXCIX'))
The output is 0, but I don't understand why?
Ruby doesn't have a post-increment operator. When it sees ++ it interprets that as one infix + followed by one prefix (unary) +. Since it expects an operand to follow after that, but instead finds the keyword end, you get a syntax error.
You need to replace x++ with x += 1.
Furthermore note that x isn't actually in scope inside the roman_to_integer method (which isn't a syntax error, but nevertheless wrong).
Additionally you'll have to replace all your ifs except the first with elsifs. The way you wrote it all the ifs are nested, which means that a) you don't have enough ends and b) the code doesn't have the semantics you want.
You are missing a closing parentheses so
puts(roman_to_integer('mcmxcix')
should be
puts roman_to_integer('mcmxcix')
or
puts(roman_to_integer('mcmxcix'))
The arr keeps getting annihilated in your while loop, and it is not in the scope outside of the loop. Move the following line above the while statement:
arr = Array.new

Resources