[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

halving a string

Chris Shea

2/2/2007 4:07:00 AM

I have a vacuum fluorescent display in my office, and I've been
messing around with it. Now that I've figured out how to communicate
with the serial connection it's time for some fun. Its shortcoming is
its 2 lines of 20 chars. So I naturally wrote a fortune cookie program
for it.

I want to make adding new fortunes easy (and without having to figure
out myself where to force a line break), so I basically need to split
a string (approximately) in half at a word boundary. This is what I
have:

class String
def halve
first_half = ''
second_half = self
until first_half.length >= length / 2
match = / /.match(second_half)
first_half << match.pre_match << ' '
second_half = match.post_match
end
[first_half.strip, second_half]
end
end

I have a feeling there's a one-line regexp that can do this. Am I
right? If not, is there a better way?

21 Answers

Trans

2/2/2007 4:20:00 AM

0



On Feb 1, 11:10 pm, "Chris Shea" <cms...@gmail.com> wrote:
> I have a vacuum fluorescent display in my office, and I've been
> messing around with it. Now that I've figured out how to communicate
> with the serial connection it's time for some fun. Its shortcoming is
> its 2 lines of 20 chars. So I naturally wrote a fortune cookie program
> for it.
>
> I want to make adding new fortunes easy (and without having to figure
> out myself where to force a line break), so I basically need to split
> a string (approximately) in half at a word boundary. This is what I
> have:
>
> class String
> def halve
> first_half = ''
> second_half = self
> until first_half.length >= length / 2
> match = / /.match(second_half)
> first_half << match.pre_match << ' '
> second_half = match.post_match
> end
> [first_half.strip, second_half]
> end
> end
>
> I have a feeling there's a one-line regexp that can do this. Am I
> right? If not, is there a better way?

untested but...

i = [0..str.size / 2].index(' ')
first_half, second_half = str[0...i], str[i..-1].strip

however, you might just prefer

require 'facets/core/string/word_wrap'
str.word_wrap(20)

T.


Chris Shea

2/2/2007 4:26:00 AM

0

On Feb 1, 9:20 pm, "Trans" <transf...@gmail.com> wrote:
> On Feb 1, 11:10 pm, "Chris Shea" <cms...@gmail.com> wrote:
>
>
>
> > I have a vacuum fluorescent display in my office, and I've been
> > messing around with it. Now that I've figured out how to communicate
> > with the serial connection it's time for some fun. Its shortcoming is
> > its 2 lines of 20 chars. So I naturally wrote a fortune cookie program
> > for it.
>
> > I want to make adding new fortunes easy (and without having to figure
> > out myself where to force a line break), so I basically need to split
> > a string (approximately) in half at a word boundary. This is what I
> > have:
>
> > class String
> > def halve
> > first_half = ''
> > second_half = self
> > until first_half.length >= length / 2
> > match = / /.match(second_half)
> > first_half << match.pre_match << ' '
> > second_half = match.post_match
> > end
> > [first_half.strip, second_half]
> > end
> > end
>
> > I have a feeling there's a one-line regexp that can do this. Am I
> > right? If not, is there a better way?
>
> untested but...
>
> i = [0..str.size / 2].index(' ')
> first_half, second_half = str[0...i], str[i..-1].strip
>
> however, you might just prefer
>
> require 'facets/core/string/word_wrap'
> str.word_wrap(20)
>
> T.

Tested, and failed. The index returns the position of the very first
space. (Also, it would have to be str[0..(str.size / 2)].index(' ')
but, still, it's no good).

Word wrapping is wrong for the occasion, as I'd like to split even
lines less than 20 chars, and have them of approximately equal length.

Bill Kelly

2/2/2007 4:58:00 AM

0

From: "Chris Shea" <cmshea@gmail.com>
>
> Tested, and failed. The index returns the position of the very first
> space. (Also, it would have to be str[0..(str.size / 2)].index(' ')
> but, still, it's no good).

rindex()

:)


Regards,

Bill



Chris Shea

2/2/2007 5:25:00 AM

0

On Feb 1, 9:57 pm, "Bill Kelly" <b...@cts.com> wrote:
> From: "Chris Shea" <cms...@gmail.com>
>
>
>
> > Tested, and failed. The index returns the position of the very first
> > space. (Also, it would have to be str[0..(str.size / 2)].index(' ')
> > but, still, it's no good).
>
> rindex()
>
> :)
>
> Regards,
>
> Bill

rindex, of course. Here's my current version then:

class String
def halve
i = self[0..(length / 2)].rindex(' ')
if i.nil?
if include?(' ')
split(' ', 1)
else
[self, '']
end
else
[self[0..i].strip, self[i..-1].strip]
end
end
end

Chris Shea

2/2/2007 5:28:00 AM

0

On Feb 1, 10:24 pm, "Chris Shea" <cms...@gmail.com> wrote:
> On Feb 1, 9:57 pm, "Bill Kelly" <b...@cts.com> wrote:
>
> > From: "Chris Shea" <cms...@gmail.com>
>
> > > Tested, and failed. The index returns the position of the very first
> > > space. (Also, it would have to be str[0..(str.size / 2)].index(' ')
> > > but, still, it's no good).
>
> > rindex()
>
> > :)
>
> > Regards,
>
> > Bill
>
> rindex, of course. Here's my current version then:
>
> class String
> def halve
> i = self[0..(length / 2)].rindex(' ')
> if i.nil?
> if include?(' ')
> split(' ', 1)
> else
> [self, '']
> end
> else
> [self[0..i].strip, self[i..-1].strip]
> end
> end
> end

ahem: split(' ', 2)

Devin Mullins

2/2/2007 6:03:00 AM

0

Naive solution:

class String
def halve(max_len=nil)
raise if max_len and size > max_len * 2 + 1
space_indices = (0...size).find_all {|i| self[i] == ' '[0] }
splitter = space_indices.sort_by {|i| (i - size/2).abs }.first
if splitter.nil? ||
(max_len && (splitter > max_len || size - splitter - 1 > max_len))
[self[0...size/2], self[size/2..-1]]
else
[self[0...splitter], self[splitter+1..-1]]
end
end
end

if __FILE__ == $0
require 'test/unit'

class SplitterTest < Test::Unit::TestCase
def test_stuff
assert_equal ['the frog', 'is green'], 'the frog is green'.halve
assert_equal ['ponchielli', 'wrote songs'],
'ponchielli wrote songs'.halve
assert_raise(RuntimeError) { 'ab d'.halve 1 }
assert_nothing_raised { 'a b'.halve 1 }
assert_equal ['lizardman', 'lives'], 'lizardman lives'.halve
assert_equal ['lizardm', 'an lives'], 'lizardman lives'.halve(8)
assert_equal ['abcdef','ghijkl'], 'abcdefghijkl'.halve
end
end
end

Chris Shea

2/2/2007 6:19:00 AM

0

On Feb 1, 11:03 pm, Devin Mullins <twif...@comcast.net> wrote:
> Naive solution:
>
> class String
> def halve(max_len=nil)
> raise if max_len and size > max_len * 2 + 1
> space_indices = (0...size).find_all {|i| self[i] == ' '[0] }
> splitter = space_indices.sort_by {|i| (i - size/2).abs }.first
> if splitter.nil? ||
> (max_len && (splitter > max_len || size - splitter - 1 > max_len))
> [self[0...size/2], self[size/2..-1]]
> else
> [self[0...splitter], self[splitter+1..-1]]
> end
> end
> end
>
> if __FILE__ == $0
> require 'test/unit'
>
> class SplitterTest < Test::Unit::TestCase
> def test_stuff
> assert_equal ['the frog', 'is green'], 'the frog is green'.halve
> assert_equal ['ponchielli', 'wrote songs'],
> 'ponchielli wrote songs'.halve
> assert_raise(RuntimeError) { 'ab d'.halve 1 }
> assert_nothing_raised { 'a b'.halve 1 }
> assert_equal ['lizardman', 'lives'], 'lizardman lives'.halve
> assert_equal ['lizardm', 'an lives'], 'lizardman lives'.halve(8)
> assert_equal ['abcdef','ghijkl'], 'abcdefghijkl'.halve
> end
> end
> end

Yes. I see how expressions like space_indices.sort_by {|i| (i - size/
2).abs }.first work, I just need to be able to think of them. It does
what I really want (get the closest space to the middle of the
string), instead of what I almost want (the last space in the first
half of the string). Maybe I just gave up too early, or started
barking up the wrong tree. I said, "I know, I'll use regular
expressions" and then I had two problems. Thanks.

Gavin Kistner

2/2/2007 6:26:00 AM

0

Chris Shea wrote:
> I want to make adding new fortunes easy (and without having to figure
> out myself where to force a line break), so I basically need to split
> a string (approximately) in half at a word boundary. This is what I
> have:
[snip[
> I have a feeling there's a one-line regexp that can do this. Am I
> right? If not, is there a better way?

This is what I would do:

strings = DATA.read.split( /\n/ )

strings.each{ |str|
puts str.gsub( /^(.{#{str.length/2},}?)\s(.+)/ ){ "#{$1}\n#{$2}" }
puts
}
#=> Hello
#=> World

#=> It's the end of the
#=> world as we know it

#=> If you didn't know any better
#=> you'd think this was magic.

__END__
Hello World
It's the end of the world as we know it
If you didn't know any better you'd think this was magic.

Robert Klemme

2/2/2007 11:53:00 AM

0

On 02.02.2007 05:26, Chris Shea wrote:
> Word wrapping is wrong for the occasion, as I'd like to split even
> lines less than 20 chars, and have them of approximately equal length.

If you want to first fill the first string and then the second you can
do this:

first, second = s.scan /.{1,20}/

For evenly distribution you could do:

irb(main):019:0> s="foo bar ajd as dashd kah sdhakjshd ahdk ahsd asjh"
=> "foo bar ajd as dashd kah sdhakjshd ahdk ahsd asjh"
irb(main):020:0> l=[40,s.length].min / 2
=> 20
irb(main):021:0> first = s[0...l]
=> "foo bar ajd as dashd"
irb(main):022:0> second = s[l...l+l]
=> " kah sdhakjshd ahdk "

If you want to break at white space, you can do it with one regexp (you
did ask for the one regexp solution :-)):

irb(main):030:0> s="aasd laksjd asdj asjkd asdj jlas d"
=> "aasd laksjd asdj asjkd asdj jlas d"
irb(main):031:0> %r[(.{1,#{s.length/2}})\s*(.{1,#{s.length/2}})] =~ s or
raise "cannot split"
=> 0
irb(main):032:0> first = $1
=> "aasd laksjd asdj"
irb(main):033:0> second = $2
=> "asjkd asdj jlas d"

Kind regards

robert

Trans

2/2/2007 1:53:00 PM

0



On Feb 1, 11:30 pm, "Chris Shea" <cms...@gmail.com> wrote:
> On Feb 1, 9:20 pm, "Trans" <transf...@gmail.com> wrote:
>
>
>
> > On Feb 1, 11:10 pm, "Chris Shea" <cms...@gmail.com> wrote:
>
> > > I have a vacuum fluorescent display in my office, and I've been
> > > messing around with it. Now that I've figured out how to communicate
> > > with the serial connection it's time for some fun. Its shortcoming is
> > > its 2 lines of 20 chars. So I naturally wrote a fortune cookie program
> > > for it.
>
> > > I want to make adding new fortunes easy (and without having to figure
> > > out myself where to force a line break), so I basically need to split
> > > a string (approximately) in half at a word boundary. This is what I
> > > have:
>
> > > class String
> > > def halve
> > > first_half = ''
> > > second_half = self
> > > until first_half.length >= length / 2
> > > match = / /.match(second_half)
> > > first_half << match.pre_match << ' '
> > > second_half = match.post_match
> > > end
> > > [first_half.strip, second_half]
> > > end
> > > end
>
> > > I have a feeling there's a one-line regexp that can do this. Am I
> > > right? If not, is there a better way?
>
> > untested but...
>
> > i = [0..str.size / 2].index(' ')
> > first_half, second_half = str[0...i], str[i..-1].strip
>
> > however, you might just prefer
>
> > require 'facets/core/string/word_wrap'
> > str.word_wrap(20)
>
> > T.
>
> Tested, and failed. The index returns the position of the very first
> space. (Also, it would have to be str[0..(str.size / 2)].index(' ')
> but, still, it's no good).

ah, size/2 has to be added to i, then it works.

> Word wrapping is wrong for the occasion, as I'd like to split even
> lines less than 20 chars, and have them of approximately equal length.

not sure i understand, the size can be set, for example:

word_wrap(str.size/2)

t.