I am trying to write a method that takes in a string that will have no spaces. All I want it to do is to return "bug" when the character in the string is a letter [A-Za-z] and to return "ant" if it's any other character.
def Letter(str)
(0..str.length).to_a do |index|
if str[index].chr =~ /[A-Za-z]/ ##I think this is where things are going wrong.
puts "bug"
else
puts "ant"
end
end
end
Does anyone have any idea how to fix this? I keep getting arrays of consecutive numbers.
Rewritten
def letter(str)
str.each_char.map do |char|
(char =~ /[[:alpha:]]/) ? 'bug' : 'ant'
end
end
In your code, you are trying to print "bug" or "ant"; but you're returning (0..str.length).to_a. This function will return an array of bugs and ants. It is also made more Rubyish:
methods should be in snake_case (lowercase, with underscores between words)
iterating over strings is easier with each_char
it's fine with [A-Za-z], but [[:alpha:]] is both clearer and handles Unicode stuff.
since we're testing each character, you know it's going to be one character long, so you don't need the start of line and end of line anchors.
def letter(str)
str.chars.each do |x|
puts x=~ /[A-Za-z]/ ? "bug" : "ant"
end
end
First things first, in your loop your are trying to convert a range
into an array.
(0..str.length).to_a
str.length returns a number, therefore making it into an array will give you an array of numbers. Hence your problem.
Second, you have to have brackets around your /a-zA-Z/ regex
Third, use the ternary operator. It's great for small if statements. Heres the syntax:
boolean ? "if boolean is true this code will execute" : "else this code will"
Fourth, use the .each methods, ruby is loved partly because of the simplicity of loops and iterating!
Happy coding!
Related
I am trying to .insert a space before the Uppercase letter if it's found.
Here's what I came up with, but it seems like it's an infinite loop. I don't know why:
def solution(string)
str = string.split("")
str.each_with_index do |l, i|
if l.upcase
str.insert(l[i], " ")
end
end
str.join("")
end
please let me know what I'm missing.
Because it's often a bad idea changing the object you're looping on. You insert a space before the upcase letter you found, so the next iteration you found the upcase letter again and everything repeats.
In this case regular expression seems to fit nicely
def solution(string)
string.gsub(/[[:upper:]]/, ' \0')
end
I want to convert all the words(alphabetic) in the string to their abbreviations like i18n does. In other words I want to change "extraordinary" into "e11y" because there are 11 characters between the first and the last letter in "extraordinary". It works with a single word in the string. But how can I do the same for a multi-word string? And of course if a word is <= 4 there is no point to make an abbreviation from it.
class Abbreviator
def self.abbreviate(x)
x.gsub(/\w+/, "#{x[0]}#{(x.length-2)}#{x[-1]}")
end
end
Test.assert_equals( Abbreviator.abbreviate("banana"), "b4a", Abbreviator.abbreviate("banana") )
Test.assert_equals( Abbreviator.abbreviate("double-barrel"), "d4e-b4l", Abbreviator.abbreviate("double-barrel") )
Test.assert_equals( Abbreviator.abbreviate("You, and I, should speak."), "You, and I, s4d s3k.", Abbreviator.abbreviate("You, and I, should speak.") )
Your mistake is that your second parameter is a substitution string operating on x (the original entire string) as a whole.
Instead of using the form of gsub where the second parameter is a substitution string, use the form of gsub where the second parameter is a block (listed, for example, third on this page). Now you are receiving each substring into your block and can operate on that substring individually.
def short_form(str)
str.gsub(/[[:alpha:]]{4,}/) { |s| "%s%d%s" % [s[0], s.size-2, s[-1]] }
end
The regex reads, "match four or more alphabetic characters".
short_form "abc" # => "abc"
short_form "a-b-c" #=> "a-b-c"
short_form "cats" #=> "c2s"
short_form "two-ponies-c" #=> "two-p4s-c"
short_form "Humpty-Dumpty, who sat on a wall, fell over"
#=> "H4y-D4y, who sat on a w2l, f2l o2r"
I would recommend something along the lines of this:
class Abbreviator
def self.abbreviate(x)
x.gsub(/\w+/) do |word|
# Skip the word unless it's long enough
next word unless word.length > 4
# Do the same I18n conversion you do before
"#{word[0]}#{(word.length-2)}#{word[-1]}"
end
end
end
The accepted answer isn't bad, but it can be made a lot simpler by not matching words that are too short in the first place:
def abbreviate(str)
str.gsub(/([[:alpha:]])([[:alpha:]]{3,})([[:alpha:]])/i) { "#{$1}#{$2.size}#{$3}" }
end
abbreviate("You, and I, should speak.")
# => "You, and I, s4d s3k."
Alternatively, we can use lookbehind and lookahead, which makes the Regexp more complex but the substitution simpler:
def abbreviate(str)
str.gsub(/(?<=[[:alpha:]])[[:alpha:]]{3,}(?=[[:alpha:]])/i, &:size)
end
I tried to write a function which will be able to randomly change letters in word except first and last one.
def fun(string)
z=0
s=string.size
tab=string
a=(1...s-1).to_a.sample s-1
for i in 1...(s-1)
puts tab[i].replace(string[a[z]])
z=z+1
end
puts tab
end
fun("sample")
My output is:
p
l
a
m
sample
Anybody know how to make it my tab be correct?
it seems to change in for block, because in output was 'plamp' so it's random as I wanted but if I want to print the whole word (splampe) it doesn't working. :(
What about:
def fun(string)
first, *middle, last = string.chars
[first, middle.shuffle, last].join
end
fun("sample") #=> "smalpe"
s = 'sample'
[s[0], s[1..-2].chars.shuffle, s[-1]].join
# => "slpmae"
Here is my solution:
def fun(string)
first = string[0]
last = string[-1]
middle = string[1..-2]
puts "#{first}#{middle.split('').shuffle.join}#{last}"
end
fun('sample')
there are some problems with your function. First, when you say tab=string, tab is now a reference to string, so, when you change characters on tab you change the string characters too. I think that for clarity is better to keep the index of sample (1....n)to reference the position in the original array.
I suggest the usage of tab as a new array.
def fun(string)
if string.length <= 2
return
z=1
s=string.size
tab = []
tab[0] = string[0]
a=(1...s-1).to_a.sample(s-1)
(1...s-1).to_a.each do |i|
tab[z] = string[a[i - 1]]
z=z+1
end
tab.push string[string.size-1]
tab.join('')
end
fun("sample")
=> "spalme"
Another way, using String#gsub with a block:
def inner_jumble(str)
str.sub(/(?<=\w)\w{2,}(?=\w)/) { |s| s.chars.shuffle.join }
end
inner_jumble("pneumonoultramicroscopicsilicovolcanoconiosis") # *
#=> "poovcanaiimsllinoonroinuicclprsciscuoooomtces"
inner_jumble("what ho, fellow coders?")
#=> "waht ho, folelw coedrs?"
(?<=\w) is a ("zero-width") positive look-behind that requires the match to immediately follow a word character.
(?=\w) is a ("zero-width") positive look-ahead that requires the match to be followed immediately by a word character.
You could use \w\w+ in place of \w{2,} for matching two or more consecutive word characters.
If you only want it to apply to individual words, you can use gsub or sub.
*A lung disease caused by inhaling very fine ash and sand dust, supposedly the longest word in some English dictionaries.
I need to create a method called palindrome?
The palindrome?(string) must determine whether a given string (word or phrase) is a palindrome, that is, it reads the same backwards as forwards, ignoring case, punctuation, and nonword characters.
I can't understand what method to use to ignore nonword characters
def palindrome?(str)
if str.reverse.downcase.delete(" ") == str.downcase.delete(" ")
return true
else
return false
end
end
I am using the ruby language and I can use Regex's, also to note that I feel that my code is too complex I know I can make it much simpler please help
def palindrome? str
str = str.gsub(/\W/, "").downcase
str.reverse == str
end
In the book I'm reading to learn Rails (RailsSpace) , the author creates two functions (below) to turn all caps city names like LOS ANGELES into Los Angeles. There's something I don't get about the first function, below, however.
Namely, where does "word" come from? I understand that "word" is a local/block variable that disappears after the function has been completed, but what is being passed into/assigned to "word." IN other words, what is being split?
I would have expected there to have been some kind of argument taking an array or hash passed into this function...and then the "each" function run over that..
def capitalize_each
space = " "
split(space).each{ |word| word.capitalize! }.join(space)
end
# Capitalize each word in place.
def capitalize_each!
replace capitalize_each end
end
Let's break this up.
split(space)
turns the string into a list of would-be words. (Actually, if the string has two spaces in a row, the list will have an empty string in it. but that doesn't matter for this purpose.) I assume this is an instance method in String; otherwise, split wouldn't be defined.
.each { |word| word.capitalize! }
.each takes each thing in the list (returned by split), and runs the following block on it, passing the thing as an arg to the block. The |word| says that this block is going to call the arg "word". So effectively, what this does is capitalize each word in the string (and each blank string and lonely bit of punctuation too, but again, that's not important -- capitalization doesn't change characters that have no concept of case).
.join(space)
glues the words back together, reinserting the space that was used to separate them before. The string it returns is the return value of the function as well.
At first I thought that the method was incomplete because of the absence of self at the beginning but it seems that even without it split is being called over the string given, space would simply be a default separator. This is how the method could look with explicit self.
class String
def capitalize_each(separator = ' ')
self.split(separator).each{|word| word.capitalize!}.join(separator)
end
end
puts "LOS ANGELES".capitalize_each #=> Los Angeles
puts "LOS_ANGELES".capitalize_each('_') #=> Los_Angeles
The string is being split by spaces, i.e. into words.
So the 'each' iterator goes through all the words, one by one, each time the word is in the 'word' object. So then for that object (word) it uses the capitalize function for it. Finally it all gets joined back together With Spaces. So The End Result is Capitalized.
These methods are meant to be defined in the String class, so what is being split is whatever string you are calling the capitalize_each method on.
Some example usage (and a slightly better implementation):
class String
def capitalize_each
split(/\s+/).each{ |word| word.capitalize! }.join " "
end
def capitalize_each!
replace capitalize_each
end
end
puts "hi, i'm a sentence".capitalize_each #=> Hi, I'm A Sentence
Think of |word| word.capitalize! as a function whch you're passing into the each method. The function has one argument (word) and simply evaluates .capitalize! on it.
Now what the each method is doing is taking each item in split(space) and evaluating your function on it. So:
"abcd".each{|x| print x}
will evaluate, in order, print "a", print "b", print "c".
http://www.ruby-doc.org/core/classes/Array.html#M000231
To demystify this behavior a bit, it helps to understand exactly what it means to "take each item in __". Basically, any object which is enumerable can be .eached in this way.
If you're referring to how it gets into your block in the first place, it's yielded into the block. #split returns an Array, and it's #each method is doing something along the lines of:
for object in stored_objects
yield object
end
This works, but if you want to turn one array into another array, it's idiomatically better to use map instead of each, like this:
words.map{|word|word.capitalize}
(Without the trailing !, capitalize makes a new string instead of modifying the old string, and map collects those new strings into a new array. In contrast, each returns the old array.)
Or, following gunn's lead:
class String
def capitalize_each
self.split(/\s/).map{|word|word.capitalize}.join(' ')
end
end
"foo bar baz".capitalize_each #=> "Foo Bar Baz"
by default, split splits on strings of spaces, but by passing a regular expression it matches each individual space characters even if they're in a row.