Can I use strip! and chomp! in one line in Ruby - ruby

I see that strip! and chomp! (and other similar methods) return nil when the string is not altered. This apparently forbids combining these methods in one line:
s = 'a' # => "a"
s.strip!.chomp!(',')
# => NoMethodError: undefined method `chomp!' for nil:NilClass
So I seem to be forced to write one per line:
s.strip! # => nil
s.chomp!(',') # => nil
Is this the only way or am I missing something?

You could use the non-mutating versions of those methods:
s = s.strip.chomp(',')
You could use a semicolon (but that would usually be poor taste):
s.strip!; s.chomp!(',')

This looks like a case where tap could be a useful tool:
s.tap {|t| t.strip!}.chomp!

R = /
^\s+ # match >= 1 whitespace at the beginning of string
| # or
,\s*$ # match comma then >= 0 whitespace at the end of the line
| # or
\s+$ # match >= 1 whitespace at the end of the line
/x
def clean(s)
s.gsub!(R,'') || s
end
In all of the following, the return value is "ab", which is also the new value of the string:
clean ' ab '
clean ' ab,'
clean ' ab, '
clean 'ab,'
clean 'ab'

Related

Get last character in string

I want to get the last character in a string MY WAY - 1) Get last index 2) Get character at last index, as a STRING. After that I will compare the string with another, but I won't include that part of code here. I tried the code below and I get a strange number instead. I am using ruby 1.8.7.
Why is this happening and how do I do it ?
line = "abc;"
last_index = line.length-1
puts "last index = #{last_index}"
last_char = line[last_index]
puts last_char
Output-
last index = 3
59
Ruby docs told me that array slicing works this way -
a = "hello there"
a[1] #=> "e"
But, in my code it does not.
UPDATE:
I keep getting constant up votes on this, hence the edit. Using [-1, 1] is correct, however a better looking solution would be using just [-1]. Check Oleg Pischicov's answer.
line[-1]
# => "c"
Original Answer
In ruby you can use [-1, 1] to get last char of a string. Here:
line = "abc;"
# => "abc;"
line[-1, 1]
# => ";"
teststr = "some text"
# => "some text"
teststr[-1, 1]
# => "t"
Explanation:
Strings can take a negative index, which count backwards from the end
of the String, and an length of how many characters you want (one in
this example).
Using String#slice as in OP's example: (will work only on ruby 1.9 onwards as explained in Yu Hau's answer)
line.slice(line.length - 1)
# => ";"
teststr.slice(teststr.length - 1)
# => "t"
Let's go nuts!!!
teststr.split('').last
# => "t"
teststr.split(//)[-1]
# => "t"
teststr.chars.last
# => "t"
teststr.scan(/.$/)[0]
# => "t"
teststr[/.$/]
# => "t"
teststr[teststr.length-1]
# => "t"
Just use "-1" index:
a = "hello there"
a[-1] #=> "e"
It's the simplest solution.
If you are using Rails, then apply the method #last to your string, like this:
"abc".last
# => c
You can use a[-1, 1] to get the last character.
You get unexpected result because the return value of String#[] changed. You are using Ruby 1.8.7 while referring the the document of Ruby 2.0
Prior to Ruby 1.9, it returns an integer character code. Since Ruby 1.9, it returns the character itself.
String#[] in Ruby 1.8.7:
str[fixnum] => fixnum or nil
String#[] in Ruby 2.0:
str[index] → new_str or nil
In ruby you can use something like this:
ending = str[-n..-1] || str
this return last n characters
Using Rails library, I would call the method #last as the string is an array. Mostly because it's more verbose..
To get the last character.
"hello there".last() #=> "e"
To get the last 3 characters you can pass a number to #last.
"hello there".last(3) #=> "ere"
Slice() method will do for you.
For Ex
"hello".slice(-1)
# => "o"
Thanks
Your code kinda works, the 'strange number' you are seeing is ; ASCII code. Every characters has a corresponding ascii code ( https://www.asciitable.com/). You can use for conversationputs last_char.chr, it should output ;.

Ruby regex match starting at specific position

In Python I can do this:
import re
regex = re.compile('a')
regex.match('xay',1) # match because string starts with 'a' at 1
regex.match('xhay',1) # no match because character at 1 is 'h'
However in Ruby, the match method seems to match everything past the positional argument. For instance, /a/.match('xhay',1) will return a match, even though the match actually starts at 2. However, I want to only consider matches that start at a specific position.
How do I get a similar mechanism in Ruby? I would like to match patterns that start at a specific position in the string as I can in Python.
/^.{1}a/
for matching a at location x+1 in the string
/^.{x}a/
--> DEMO
How about below using StringScanner ?
require 'strscan'
scanner = StringScanner.new 'xay'
scanner.pos = 1
!!scanner.scan(/a/) # => true
scanner = StringScanner.new 'xnnay'
scanner.pos = 1
!!scanner.scan(/a/) # => false
Regexp#match has an optional second parameter pos, but it works like Python's search method. You could however check if the returned MatchData begins at the specified position:
re = /a/
match_data = re.match('xay', 1)
match_data.begin(0) == 1
#=> true
match_data = re.match('xhay', 1)
match_data.begin(0) == 1
#=> false
match_data = re.match('áay', 1)
match_data.begin(0) == 1
#=> true
match_data = re.match('aay', 1)
match_data.begin(0) == 1
#=> true
Extending a little bit on what #sunbabaphu answered:
def matching_at_pos(x=0, regex)
/\A.{#{x-1}}#{regex}/
end # note the position is 1 indexed
'xxa' =~ matching_at_pos(2, /a/)
=> nil
'xxa' =~ matching_at_pos(3, /a/)
=> 0
'xxa' =~ matching_at_pos(4, /a/)
=> nil
The answer to this question is \G.
\G matches the starting point of the regex match, when calling the two-argument version of String#match that takes a starting position.
'xay'.match(/\Ga/, 1) # match because /a/ starts at 1
'xhay'match(/\Ga/, 1) # no match because character at 1 is 'h'

Ruby Regexp#match to match start of string with given position (Python re-like)

I'm looking for a way to match strings from first symbol, but considering the offset I give to match method.
test_string = 'abc def qwe'
def_pos = 4
qwe_pos = 8
/qwe/.match(test_string, def_pos) # => #<MatchData "qwe">
# ^^^ this is bad, as it just skipped over the 'def'
/^qwe/.match(test_string, def_pos) # => nil
# ^^^ looks ok...
/^qwe/.match(test_string, qwe_pos) # => nil
# ^^^ it's bad, as it never matches 'qwe' now
what I'm looking for is:
/...qwe/.match(test_string, def_pos) # => nil
/...qwe/.match(test_string, qwe_pos) # => #<MatchData "qwe">
Any ideas?
How about using a string slice?
/^qwe/.match(test_string[def_pos..-1])
The pos parameter tells the regex engine where to start the match, but it doesn't change the behaviour of the start-of-line (and other) anchors. ^ still only matches at the start of a line (and qwe_pos is still in the middle of test_string).
Also, in Ruby, \A is the "start-of-string" anchor, \z is the "end-of-string" anchor. ^ and $ match starts/ends of lines, too, and there is no option to change that behavior (which is special to Ruby, just like the charmingly confusing use of (?m) which does what (?s) does in other regex flavors)...

Ruby: How to get the first character of a string

How can I get the first character in a string using Ruby?
Ultimately what I'm doing is taking someone's last name and just creating an initial out of it.
So if the string was "Smith" I just want "S".
You can use Ruby's open classes to make your code much more readable. For instance, this:
class String
def initial
self[0,1]
end
end
will allow you to use the initial method on any string. So if you have the following variables:
last_name = "Smith"
first_name = "John"
Then you can get the initials very cleanly and readably:
puts first_name.initial # prints J
puts last_name.initial # prints S
The other method mentioned here doesn't work on Ruby 1.8 (not that you should be using 1.8 anymore anyway!--but when this answer was posted it was still quite common):
puts 'Smith'[0] # prints 83
Of course, if you're not doing it on a regular basis, then defining the method might be overkill, and you could just do it directly:
puts last_name[0,1]
If you use a recent version of Ruby (1.9.0 or later), the following should work:
'Smith'[0] # => 'S'
If you use either 1.9.0+ or 1.8.7, the following should work:
'Smith'.chars.first # => 'S'
If you use a version older than 1.8.7, this should work:
'Smith'.split(//).first # => 'S'
Note that 'Smith'[0,1] does not work on 1.8, it will not give you the first character, it will only give you the first byte.
"Smith"[0..0]
works in both ruby 1.8 and ruby 1.9.
For completeness sake, since Ruby 1.9 String#chr returns the first character of a string. Its still available in 2.0 and 2.1.
"Smith".chr #=> "S"
http://ruby-doc.org/core-1.9.3/String.html#method-i-chr
In MRI 1.8.7 or greater:
'foobarbaz'.each_char.first
Try this:
>> a = "Smith"
>> a[0]
=> "S"
OR
>> "Smith".chr
#=> "S"
In Rails
name = 'Smith'
name.first
>> s = 'Smith'
=> "Smith"
>> s[0]
=> "S"
Another option that hasn't been mentioned yet:
> "Smith".slice(0)
#=> "S"
Because of an annoying design choice in Ruby before 1.9 — some_string[0] returns the character code of the first character — the most portable way to write this is some_string[0,1], which tells it to get a substring at index 0 that's 1 character long.
Try this:
def word(string, num)
string = 'Smith'
string[0..(num-1)]
end
If you're using Rails You can also use truncate
> 'Smith'.truncate(1, omission: '')
#=> "S"
or for additional formatting:
> 'Smith'.truncate(4)
#=> "S..."
> 'Smith'.truncate(2, omission: '.')
#=> "S."
While this is definitely overkill for the original question, for a pure ruby solution, here is how truncate is implemented in rails
# File activesupport/lib/active_support/core_ext/string/filters.rb, line 66
def truncate(truncate_at, options = {})
return dup unless length > truncate_at
omission = options[:omission] || "..."
length_with_room_for_omission = truncate_at - omission.length
stop = if options[:separator]
rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
else
length_with_room_for_omission
end
"#{self[0, stop]}#{omission}"
end
Other way around would be using the chars for a string:
def abbrev_name
first_name.chars.first.capitalize + '.' + ' ' + last_name
end
Any of these methods will work:
name = 'Smith'
puts name.[0..0] # => S
puts name.[0] # => S
puts name.[0,1] # => S
puts name.[0].chr # => S

In Ruby language, how can I get the number of lines in a string?

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

Resources