So it reads from a online source file
the string look like this,
1. this is line1.X
2. this is "line2X"
3. this is X line4.
4. this is line3.X.X
So I only wants to put out the whole string with the ending "X" removed. In this example, only the X at the end of line 1 and line 4 will be removed.
I used chomp, but it only removed the X in line4.
string.each_line { |line| line.chomp("X") }
Should I use chomp or use something else?
String#chomp will work if you change the record separator to include both your chosen character and a newline. For example:
string.each_line { |line| puts line.chomp("X\n") }
The code above will print:
1. this is line1.
2. this is "line2X"
3. this is X line4.
4. this is line3.X.
but it will still return the original string. This may or may not matter for your use case. If it does matter, then you may want to use Kernel#p and String#gsub instead. For example:
p string.gsub(/X$/, '')
#=> "1. this is line1.\n2. this is \"line2X\"\n3. this is X line4.\n4. this is line3.X.\n"
string
#=> "1. this is line1.X\n2. this is \"line2X\"\n3. this is X line4.\n4. this is line3.X.X\n"
Try this:
string.each_line { |line|
if line[-1] = 'X'
line.chop!
end
}
Why not just use gsub?
text =<<_
1. this is line1.X
2. this is "line2X"
3. this is X line4.
4. this is line3.X.X
_
puts text.gsub(/X$/,'')
# 1. this is line1.
# 2. this is "line2X"
# 3. this is X line4.
# 4. this is line3.X.
Related
I answered my own question. Forgot to initialize count = 0
I have a bunch of sentences in a paragraph.
a = "Hello there. this is the best class. but does not offer anything." as an example.
To figure out if the first letter is capitalized, my thought is to .split the string so that a_sentence = a.split(".")
I know I can "hello world".capitalize! so that if it was nil it means to me that it was already capitalized
EDIT
Now I can use array method to go through value and use '.capitalize!
And I know I can check if something is .strip.capitalize!.nil?
But I can't seem to output how many were capitalized.
EDIT
a_sentence.each do |sentence|
if (sentence.strip.capitalize!.nil?)
count += 1
puts "#{count} capitalized"
end
end
It outputs:
1 capitalized
Thanks for all your help. I'll stick with the above code I can understand within the framework I only know in Ruby. :)
Try this:
b = []
a.split(".").each do |sentence|
b << sentence.strip.capitalize
end
b = b.join(". ") + "."
# => "Hello there. This is the best class. But does not offer anything."
Your post's title is misleading because from your code, it seems that you want to get the count of capitalized letters at the beginning of a sentence.
Assuming that every sentence is finishing on a period (a full stop) followed by a space, the following should work for you:
split_str = ". "
regex = /^[A-Z]/
paragraph_text.split(split_str).count do |sentence|
regex.match(sentence)
end
And if you want to simply ensure that each starting letter is capitalized, you could try the following:
paragraph_text.split(split_str).map(&:capitalize).join(split_str) + split_str
There's no need to split the string into sentences:
str = "It was the best of times. sound familiar? Out, damn spot! oh, my."
str.scan(/(?:^|[.!?]\s)\s*\K[A-Z]/).length
#=> 2
The regex could be written with documentation by adding x after the closing /:
r = /
(?: # start a non-capture group
^|[.!?]\s # match ^ or (|) any of ([]) ., ! or ?, then one whitespace char
) # end non-capture group
\s* # match any number of whitespace chars
\K # forget the preceding match
[A-Z] # match one capital letter
/x
a = str.scan(r)
#=> ["I", "O"]
a.length
#=> 2
Instead of Array#length, you could use its alias, size, or Array#count.
You can count how many were capitalized, like this:
a = "Hello there. this is the best class. but does not offer anything."
a_sentence = a.split(".")
a_sentence.inject(0) { |sum, s| s.strip!; s.capitalize!.nil? ? sum += 1 : sum }
# => 1
a_sentence
# => ["Hello there", "This is the best class", "But does not offer anything"]
And then put it back together, like this:
"#{a_sentence.join('. ')}."
# => "Hello there. This is the best class. But does not offer anything."
EDIT
As #Humza sugested, you could use count:
a_sentence.count { |s| s.strip!; s.capitalize!.nil? }
# => 1
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 am trying to get a simple Ruby program to run correctly.
I need it to take user input until the user types q for "quit". It also needs to capitalize the last four letters of the users input and, with input under four letters, to capitalize all letters.
It only works for input over four letters, and, when I type "quit", it gets a nil error.
See the code below.
I am using Eclipse with Ruby 2.0.
puts ("\n" * 10)
loop do
puts "Please enter a word. (To quit type q.)" # Gets the users input
puts ("\n" * 3) #Scroll the screen 3 times
str = gets.chomp #Collect the player's response
puts ("\n" * 3) #Scroll the screen 3 times
length = str.length # Counts length of string
str = str[0..(length-5)] + str[(length-4)..length].upcase # Only makes last four letters of user input capitalized
puts str # Shows on screen the user input with capitalized last four letters
puts ("\n" * 3) #Scroll the screen 3 times
break if str == "q"
end
You need to pay attention to [] when you write code like this:
str = str[0..(length-5)] + str[(length-4)..length].upcase
If an index is negative, it is counted from the end of string. For example:
str = "abcde"
str[-1] # => "e"
str[-2] #=> "d"
See String.[] for more details.
With regard to your question, here is my logic:
break if str == "q"
if str.length < 4
str = str.upcase
else
str = str[0...-4] + str[-4..-1].upcase
end
p str
You need to do some checks on your length. If length is less than 4, than length - 5 will return a negative number and your
str[0..(length-5)] + ...
line will be upset. For example. If you type "str", then your code will try to do:
length = 3
str[0..-2] + str[-1..3]
which doesn't make sense. Also, since you check for str == "q" at the end, this is likely also happening for "q". Move your check and break up in the block, and make sure you don't treat all strings as if they're going to be longer than 4 characters.
In Ruby language, how can I get the number of lines in a string?
There is a lines method for strings which returns an Enumerator. Call count on the enumerator.
str = "Hello\nWorld"
str.lines.count # 2
str = "Hello\nWorld\n" # trailing newline is ignored
str.lines.count # 2
The lines method was introduced in Ruby 1.8.7. If you're using an older version, checkout the answers by #mipadi and #Greg.
One way would be to count the number of line endings (\n or \r\n, depending on the string), the caveat being that if the string does not end in a new line, you'll have to make sure to add one to your count. You could do so with the following:
c = my_string.count("\n")
c += 1 unless c[-1,1] == "\n"
You could also just loop through the string and count the lines:
c = 0
my_string.each { |line| c += 1 }
Continuing with that solution, you could get really fancy and use inject:
c = my_string.each.inject(0) { |count, line| count += 1 }
string".split("\n").size works nicely. I like that it ignores trailing new-lines if they don't contain content.
"Hello\nWorld\n".split("\n") # => ["Hello", "World"]
"hello\nworld\nfoo bar\n\n".split("\n").size # => 3
That might not be what you want, so use lines() as #Anurag suggested instead if you need to honor all new-lines.
"hello\nworld\nfoo bar\n\n".lines.count # => 4
"hello\nworld\nfoo bar\n\n".chomp.split("\n",-1).size # => 4
String#chomp gets rid of an end of line if it exists, and the -1 allows empty strings.
given a file object (here, in rails)
file = File.open(File.join(Rails.root, 'lib', 'file.json'))
file.readlines.count
returns the number of lines
IO#readlines performs a split method on strings (IOStrings in this case) using newlines as the separator
This will not count blank lines:
string.split("\n").select{ |line| line != "" }.size
One\n
Two\n
Three\n
Four\n
remove_lines(2) would remove the first two lines, leaving the string:
Three\n
Four\n
s.to_a[2..-1].join
>> s = "One\nTwo\nThree\nFour\n"
=> "One\nTwo\nThree\nFour\n"
>> s.to_a[2..-1].join
=> "Three\nFour\n"
s = "One\nTwo\nThree\nFour"
lines = s.lines
> ["One\n", "Two\n", "Three\n", "Four"]
remaining_lines = lines[2..-1]
> ["Three\n", "Four"]
remaining_lines.join
> "Three\nFour"
String#lines converts the string into an array of lines (retaining the new line character at the end of each string)
[2..-1] specifies the range of lines to return, in this case the third through the last
Array#join concatenates the lines back together, without any space (but since the lines still contain the new line character, we don't need a separator)
In one line:
s.lines[2..-1].join
class String
def remove_lines(i)
split("\n")[i..-1].join("\n")
end
end
Calling "One\nTwo\nThree\nFour\n".remove_lines(2) would result in "Three\nFour". If you need the trailing "\n" you need to extend this method accordingly.
I had a situation where I needed to support multiple platform EOLN (both \r and \n), and had success with the following:
split(/\r\n|\r|\n/, 2).last
Or the equivalent remove_lines:
def remove_lines(number_of_lines=1)
split(/\r\n|\r|\n/, number_of_lines+1).last
end
Here is a pure regexp one-liner. Hypothetically it should be even faster than the elegant solution provided by #DigitalRoss:
n = 4 # number of lines
str.gsub(/\A(.*\n){#{n}}/,'')
If you know in advance how many line you want to cut (4 here):
str.gsub(/\A(.*\n){4}/,'')
And if you want to cut only one line:
str.gsub(/\A.*\n/,'')
In order to cut n lines from the tail:
gsub(/(\n.*){#{n}}\Z/,'')
This problem will remove the first two lines using regular expression.
Text = "One\nTwo\nThree\nFour"
Text = Text.gsub /^(?:[^\n]*\n){2}/, ''
# -----------------------------------^^ (2) Replace with nothing
# ----------------^^^^^^^^^^^^^^^^ (1) Detect first 2 lines
puts Text
EDIT: I've just saw that the question is also about 'n' lines not just two lines.
So here is my new answer.
Lines_Removed = 2
Original_Text = "One\nTwo\nThree\nFour"
Result___Text = (Original_Text.gsub(Regexp.new("([^\n]*\n){%s}" % Lines_Removed), ''))
# ^^^^^^^^^^^^^^ ^^
# - (1) Detect first lines -----++++++++++++++ ||
# - (2) Replace with nothing -----------------------------------------------------++
puts Result___Text # Returns "Three\nFour"
def remove_lines(str, n)
res = ""
arr = str.split("\n")[n..(str.size-n)]
arr.each { |i| res.concat(i + "\n") }
return res
end
a = "1\n2\n3\n4\n"
b = remove_lines(a, 2)
print b