Getting the last N bytes of a string:

What’s the simplest way to get only the last 10 bytes of a string?

buf[-10,10]

doesn’t work if buf is smaller than 10 bytes, as it returns nil. Is
there
anything simpler than

buf[-10,10] || buf

?

Thanks,

Brian.

P.S. To get the first 10 bytes of a string is easy: buf[0,10] always
works, whether or not buf is smaller than 10 bytes)

buf.reverse[0,10]?

On 6/1/07, Brian C. [email protected] wrote:

Thanks,

Brian.

P.S. To get the first 10 bytes of a string is easy: buf[0,10] always
works, whether or not buf is smaller than 10 bytes)

I don’t know if this is simple but you can try something like this.

str =~ /(.{1,10}$)/

Harry

A Look into Japanese Ruby List in English
http://www.kakueki.com/

On 6/1/07, Harry K. [email protected] wrote:

str =~ /(.{1,10}$)/

This works nicely if you do this:
str[/(.{1,10}$)/]

Though I guess it depends on what you consider “simple”.

Brian C. wrote:

What’s the simplest way to get only the last 10 bytes of a string?

There are several ways. One option is to pad the string with spaces,
extract your slice, then strip the leading and trailing whitespace:

buf = “abcdef”

buf.rjust(10, ’ ')[-10, 10].strip

=> “abcdef”

David

Brian C. wrote:

What’s the simplest way to get only the last 10 bytes of a string?

Ok. Here is my first attempt at answering a coding question. /deep
breath

‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’.reverse.slice(0…9).reverse

On 6/2/07, Bertram S. [email protected] wrote:

is what the OP meant.

That is a great answer too :slight_smile:
I guess the OP didn’t mention newlines, so \z works better.

Brian C. wrote:

What’s the simplest way to get only the last 10 bytes of a string?

buf[-10,10]

doesn’t work if buf is smaller than 10 bytes, as it returns nil. Is there
anything simpler than

buf[-10,10] || buf

I’d use:

buf[-10…-1] || buf

but this is only a variation of what you have.

There is buf.reverse[0…9].reverse as well, but this looks even uglier
to me than the first.

Stefan

Hi,

Am Freitag, 01. Jun 2007, 22:10:51 +0900 schrieb Leonard C.:

On 6/1/07, Harry K. [email protected] wrote:

str =~ /(.{1,10}$)/

This works nicely if you do this:
str[/(.{1,10}$)/]

str[/(.{1,10}\z)/]

is what the OP meant.

Bertram

On 6/1/07, Leonard C. [email protected] wrote:

On 6/1/07, Harry K. [email protected] wrote:

str =~ /(.{1,10}$)/

This works nicely if you do this:
str[/(.{1,10}$)/]

Though I guess it depends on what you consider “simple”.

Well, I guess the parentheses are not necessary.
This looks a little less cluttered.

str[/.{1,10}$/]

Harry

A Look into Japanese Ruby List in English
http://www.kakueki.com/

Thanks everyone for your answers.

I think I’ll stick with buf[-10,10] || buf. I was just wondering if I’d
missed something obvious like buf.last(10), after staring at ‘ri String’
too
long.

Finally I found a usage case where perl has the edge :slight_smile:

$ perl -e ‘$a=“abc”;print substr($a,-10),"\n"’
abc
$ perl -e ‘$a=“abcdefghijklmnop”;print substr($a,-10),"\n"’
ghijklmnop

Regards,

Brian.

Hi,

Am Freitag, 01. Jun 2007, 20:15:54 +0900 schrieb Brian C.:

What’s the simplest way to get only the last 10 bytes of a string?

buf[-10,10]

doesn’t work if buf is smaller than 10 bytes, as it returns nil. Is there
anything simpler than

buf[-10,10] || buf

?

,From time to time I find myself trying to do something like
that. Maybe the best thing was if the String#slice method
were defined for using negative lengths but that’s probably
too late.

For my personal use I wrote a litte extension doing exactly
that. You can have it if you want.

http://www.bertram-scharpf.de/tmp/bs-ruby.tar.gz

Inspite of its shortness it’s surely buggy. Parameter
definition will ever be a matter of taste. Don’t try to
convince the core developpers there’s a neccessity to proffer
a solution for this. No chance.

Bertram

ok, I have a question now. In the original post, he wanted to cover
errors caused by undersized strings. I have been trying to grok the
“zen of ruby” from posts in here and I thought that writing Ruby-ish
code involves two things: 1. making it so that it reads as plain
English and 2. Letting Ruby do the work for you.

I could do it easily enough in Pascal, for example:

s := @s[length(s) - 10];

but then we need to check for length errors as mentioned before.

Here comes the question, why was my approach wrong? I am assuming that
it was horrible because no one even bothered to tell me that I was being
a total goober by saying this:

‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’.reverse.slice(0…9).reverse

I know that just having working code is not enough or we could use C#
and have done with it. How do we make it readable? How do we let Ruby
do the work?

It seems to me that approaches like str[/(.{1,10}\z)/] are neither plain
language readable nor letting Ruby do the work as it seems that the work
is in the coding.

Assuming that all the variations work equally well, how does one choose
which is the more “ruby like” in its approach? How can I tell which
approach is ugly and which is elegant?

On Jun 1, 2007, at 23:14 , Brian C. wrote:

I think I’ll stick with buf[-10,10] || buf. I was just wondering if
I’d
missed something obvious like buf.last(10), after staring at ‘ri
String’ too
long.

you could do that too:

“blah blah blah”.split(//).last(4).join
=> “blah”

or do what you were looking for:

class String; def last(n=1); self[-n, n] || self; end; end
=> nil

“blah”.last(10)
=> “blah”

“blah blah”.last(4)
=> “blah”

On Jun 2, 2007, at 10:07 AM, Lloyd L. wrote:

but then we need to check for length errors as mentioned before.
and have done with it. How do we make it readable? How do we let
choose
which is the more “ruby like” in its approach? How can I tell which
approach is ugly and which is elegant?


Posted via http://www.ruby-forum.com/.

Well, this is how Rails solves this in ActiveSupport

vendor/rails/activesupport/lib/active_support/core_ext/string/access.rb

module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc:
module String #:nodoc:
# Makes it easier to access parts of a string, such as
specific characters and substrings.
module Access
#snip
# Returns the last character of the string or the last +limit

  • characters.
    #
    # Examples:
    # “hello”.last # => “o”
    # “hello”.last(2) # => “lo”
    # “hello”.last(10) # => “hello”
    def last(limit = 1)
    (chars[(-limit)…-1] || self).to_s
    end
    end
    end
    end
    end

Which is mixed into String by:
vendor/rails/activesupport/lib/active_support/core_ext/string.rb

require File.dirname(FILE) + ‘/string/inflections’
require File.dirname(FILE) + ‘/string/conversions’
require File.dirname(FILE) + ‘/string/access’
require File.dirname(FILE) + ‘/string/starts_ends_with’
require File.dirname(FILE) + ‘/string/iterators’
require File.dirname(FILE) + ‘/string/unicode’

class String #:nodoc:
include ActiveSupport::CoreExtensions::String::Access
include ActiveSupport::CoreExtensions::String::Conversions
include ActiveSupport::CoreExtensions::String::Inflections
include ActiveSupport::CoreExtensions::String::StartsEndsWith
include ActiveSupport::CoreExtensions::String::Iterators
include ActiveSupport::CoreExtensions::String::Unicode
end

So I’d venture to say that the Ruby Way is to simply open up the
String class and give it a new method. Since there is already an
Array#first that gives [1,2,3,4].first(2) => [1,2], it just seems
right to match that with .last and move the pair onto String treating
the individual characters like the elements of the Array.

Although the longer-term would seem to be to reconcile the []
behavior with Ranges:

“abcde”[0…3]
=> “abc”
“abcde”[-3…-1]
=> “cde”
“abcdefghijklmno”[-10…-1]
=> “fghijklmno”
“abcdefghijklmno”[0…10]
=> “abcdefghij”
“abcd”[0…10]
=> “abcd”

“abcd”[-10…-1]
=> nil

If only that were also “abcd”.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

What would be the chances of getting something added to the core? It
seems to me that a new kind of slice would be in order. I know that
there are lTrim() and rTrim() (left and right) in other languages. What
about l_Slice and r_Slice? Then, it would be:

p ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’.r_slice(0…9)

Hi,

Am Dienstag, 12. Jun 2007, 23:50:36 +0900 schrieb Lloyd L.:

What would be the chances of getting something added to the core?

This is what I would have liked to propose.

If anyone understood the `notempty?’ proposal.

Bertram

On 2007-06-04 10:40:32 -0700, Ryan D. [email protected]
said:

=> “blah”

or do what you were looking for:

class String; def last(n=1); self[-n, n] || self; end; end
=> nil
“blah”.last(10)
=> “blah”
“blah blah”.last(4)
=> “blah”

“blah blah blah”.to_a.last(4).join as well.

It seems like a lot of Array methods would be better served as
equivalents from Enumerable. #last is one of these.

(It won’t nearly be as fast as a pure Array implementation, but it
would be extremely useful.)

p ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’.r_slice(0…9)

What about this:

def last_bytes(s, number_of_bytes)
if s.size > number_of_bytes then
return s.slice(s.size - number_of_bytes…s.size)
end
return s
end

p last_bytes(‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’, 10)
p last_bytes(‘WXYZ’, 10)

this is the result:

“QRSTUVWXYZ”
“WXYZ”

On 13-Jun-07, at 10:15 AM, bbiker wrote:

irb(main):001:0> str = “now is the”
=> “now is the”
irb(main):002:0> str[-10…-1]
=> “now is the”

So I really see no need for a special method to obtain the last x
bytes of a string.

str[-100…-1]
=> nil

Cheers,
Bob


Bob H. – tumblelog at <http://
www.recursive.ca/so/>
Recursive Design Inc. – weblog at <http://www.recursive.ca/
hutch>
– works at http://www.recursive.ca/