# String manipulation

How to add “-” between the numbers
Eg:
123456789123456789 as 12-3456-7891-2345-6789

siva kumar wrote:

How to add “-” between the numbers
Eg:
123456789123456789 as 12-3456-7891-2345-6789

irb(main):001:0> str = “123456789123456789”
=> “123456789123456789”
irb(main):002:0> str.reverse.gsub(/…/, “\0-”).reverse
=> “12-3456-7891-2345-6789”

irb(main):001:0> str = “123456789123456789”
=> “123456789123456789”
irb(main):002:0> str.reverse.gsub(/…/, “\0-”).reverse
=> “12-3456-7891-2345-6789”

Alex

That’s awesome! But doesn’t guarantee 2 digits at the start (who knows
what
the OP needs).

I was messing with:

str.scan(/(…)(.*)/).first.map {|e|
e.length>4?e.scan(/.{1,4}/):e}.join(’-’)

which is awful, then I got:

str.sub(/\d{2}/,’\0-’).gsub(/\d{4}(?!\$)/,’\0-’)

Which is… probably even worse.

ben

On 27/06/06, Ben N. [email protected] wrote:

I was messing with:

str.scan(/(…)(.*)/).first.map {|e| e.length>4?e.scan(/.{1,4}/):e}.join(’-’)

which is awful, then I got:

str.sub(/\d{2}/,’\0-’).gsub(/\d{4}(?!\$)/,’\0-’)

Which is… probably even worse.

str.gsub(/(?:^\d{2}|\d{4}(?=.))/, ‘\0-’)

Paul

I really like Alex’s solution to this. As a newbie, I always attempt
these “easy” things just to help me learn more of the language. In this
case, I got stymied by what I consider to be a failure of Ruby’s “least
surprise” efforts.

My solution involved reversing the string as Alex did, and then trying
to use “each_with_index” on it to iterate through the characters. (‘with
index’, so I could use index % 4 to place the dashes) I have come to
understand that in this case, “each” doesn’t mean “each character”.
Surprise!

My question is, is String#scan(/./) the best way to convert a string
into an array so that one could then use Array#each or
Array#each_with_index to mess with the characters? It seems to work in
irb, but I’m guessing there are some corner cases where the regexp would
falter. Also seems more computationally intensive that should be
necessary to just split it up into characters.

Also, my first thought on a solution for this was to simply walk along
the string and insert dashes where appropriate. Why isn’t there a
“String#insert(where,str)” method? Inserting substrings into strings
seems like such a common thing to do.

And finally, a question about Alex’s gsub. I don’t quite follow the
“\0-” syntax. It appears related to the group matching discussed on
page 326 of pickaxe, but not quite. Clearly in the “\0-” sequence we
have the first slash escaping the second one, so it is effectively \0
plus the ‘-’, in other words replace the four characters matched with
the four characters plus a dash. What I don’t get is how \0 outside of
the pattern is giving us anything useful. Seems like it should be \$1
instead, since it is outside of the regular expression being matched.
But then, there aren’t any parenthesis, so there is no group, so perhaps
\$1 doesn’t apply either. Can someone offer some clarification?

thanks,
jp

Alex Y. wrote:

siva kumar wrote:

How to add “-” between the numbers
Eg:
123456789123456789 as 12-3456-7891-2345-6789

irb(main):001:0> str = “123456789123456789”
=> “123456789123456789”
irb(main):002:0> str.reverse.gsub(/…/, “\0-”).reverse
=> “12-3456-7891-2345-6789”

-----Original Message-----
From: Paul B. [mailto:[email protected]]
[…]
On 27/06/06, Ben N. [email protected] wrote:

then I got:

str.sub(/\d{2}/,’\0-’).gsub(/\d{4}(?!\$)/,’\0-’)

str.gsub(/(?:^\d{2}|\d{4}(?=.))/, ‘\0-’)

Paul

Although it’s derivative, if you sacrifice a little precision (bad
inputs
will kill the regexp solutions anyway) then:

str.gsub(/^…|.{4}(?!\$)/,’\0-’)

seems to work for me…

ben

On 6/27/06, Jeff P. [email protected] wrote:

My question is, is String#scan(/./) the best way to convert a string
into an array so that one could then use Array#each or
Array#each_with_index to mess with the characters? It seems to work in
irb, but I’m guessing there are some corner cases where the regexp would
falter. Also seems more computationally intensive that should be
necessary to just split it up into characters.

Try String#each_byte and then .chr the numeric byte value.

Also, my first thought on a solution for this was to simply walk along
the string and insert dashes where appropriate. Why isn’t there a
“String#insert(where,str)” method? Inserting substrings into strings
seems like such a common thing to do.

You mean like String#insert it is there, of course there is no
insert!, so you have to remember to save the result.

And finally, a question about Alex’s gsub. I don’t quite follow the
“\0-” syntax. It appears related to the group matching discussed on
page 326 of pickaxe, but not quite. Clearly in the “\0-” sequence we
have the first slash escaping the second one, so it is effectively \0
plus the ‘-’, in other words replace the four characters matched with
the four characters plus a dash. What I don’t get is how \0 outside of
the pattern is giving us anything useful. Seems like it should be \$1
instead, since it is outside of the regular expression being matched.
But then, there aren’t any parenthesis, so there is no group, so perhaps
\$1 doesn’t apply either. Can someone offer some clarification?

This is as documented and an artifact of Ruby’s history (i.e. a
Perlism), which in turn was a sedism, which was brought in from ed…

pth

-----Original Message-----
From: [email protected]
[mailto:[email protected]] On Behalf Of Jeff P.
Sent: Wednesday, June 28, 2006 8:52 AM
To: ruby-talk ML
Subject: Re: string manipulation

I really like Alex’s solution to this. As a newbie, I always attempt
language.

I’ve not been programming ruby for long, so these nasty oneliners amuse
me
greatly, as well.

My solution involved reversing the string as Alex did, and
then trying
to use “each_with_index” on it to iterate through the
characters.

The biggest problem I had with the String#each or String#each_with_index
approach is that you don’t get a string out of it at the end, you get an
array. This means you need to operate directly on the string inside your
block, which may or may not be pretty.

Also, my first thought on a solution for this was to simply
walk along
the string and insert dashes where appropriate. Why isn’t there a
“String#insert(where,str)” method? Inserting substrings into strings
seems like such a common thing to do.

As someone else pointed out, String#insert does exist. For the given
string
you can do:

[2,7,12,17].inject(“123456789123456789”) {|string, index|
string.insert(index,’-’)}

Which is quite nice, and shows off inject, which is AWESOME.

Sadly, to call it a real oneliner you’d need to construct that initial
array, which I was unable to do in a manner I consider fit for print.
Another way to attack the same thing, though, would be with Range#step:

(2…str.length-1).step(5) {|index| str.insert(index,’-’)}

Which is also not ugly, but check the way it handles cases that have
different lengths to the OP’s string - the /…/ double reverse, the
regexp
and the ‘insert at index’ approaches all behave different ways; not all
of
which are likely “correct”.

Can someone offer some clarification?

I think you should look again at Paul B.'s approach, which is
(IMVHO)
actually the most readable and elegant approach, once you take out the
redundant passive grouping (as done here):

str.gsub(/^\d{2}|\d{4}(?=.)/, ‘\0-’)

Once deconstructed, it’s looking for start followed by two numbers, OR
any
four numbers, provided they are followed by another character (you could
also write (?!\$) for not end-of-line). If it finds one of those it
appends a
dash. Personally, I could look at this solution and say what it is
supposed
to do without running it (and without bending my brain). Only the
explicit
inject example above rings my readability meter as loudly.

thanks,
jp

Cheers,

ben

Thanks, I guess it is an omission at:
http://www.rubycentral.com/ref/

no sign of string#insert there

jp

Patrick H. wrote:

On 6/27/06, Jeff P. [email protected] wrote:

My question is, is String#scan(/./) the best way to convert a string
into an array so that one could then use Array#each or
Array#each_with_index to mess with the characters? It seems to work in
irb, but I’m guessing there are some corner cases where the regexp would
falter. Also seems more computationally intensive that should be
necessary to just split it up into characters.

Try String#each_byte and then .chr the numeric byte value.

Also, my first thought on a solution for this was to simply walk along
the string and insert dashes where appropriate. Why isn’t there a
“String#insert(where,str)” method? Inserting substrings into strings
seems like such a common thing to do.

You mean like String#insert it is there, of course there is no
insert!, so you have to remember to save the result.

And finally, a question about Alex’s gsub. I don’t quite follow the
“\0-” syntax. It appears related to the group matching discussed on
page 326 of pickaxe, but not quite. Clearly in the “\0-” sequence we
have the first slash escaping the second one, so it is effectively \0
plus the ‘-’, in other words replace the four characters matched with
the four characters plus a dash. What I don’t get is how \0 outside of
the pattern is giving us anything useful. Seems like it should be \$1
instead, since it is outside of the regular expression being matched.
But then, there aren’t any parenthesis, so there is no group, so perhaps
\$1 doesn’t apply either. Can someone offer some clarification?

This is as documented and an artifact of Ruby’s history (i.e. a
Perlism), which in turn was a sedism, which was brought in from ed…

pth

On Jun 27, 2006, at 2:01 AM, siva kumar wrote:

How to add “-” between the numbers
Eg:
123456789123456789 as 12-3456-7891-2345-6789

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

require ‘enumerator’
s = 123456789123456789.to_s
s.split(//).reverse.to_enum(:each_slice, 4).inject{|a,v|
[a,’-’,v]}.flatten.reverse.join

On Jun 28, 2006, at 7:24, Jeff P. wrote:

Thanks, I guess it is an omission at:
http://www.rubycentral.com/ref/

no sign of string#insert there

rubycentral seems to be using the 1.6 versions of the documentation
(it is marked as ‘old’ on the homepage).

http://www.ruby-doc.org has the current documentation online, and
String#insert exists there.

matthew smillie.

On 6/28/06, Jeff P. [email protected] wrote:

Thanks, I guess it is an omission at:
http://www.rubycentral.com/ref/

no sign of string#insert there

Always try ri.

ri String
ri String#insert

pth

siva kumar wrote:

How to add “-” between the numbers
Eg:
123456789123456789 as 12-3456-7891-2345-6789

irb(main):001:0> s = 123456789123456789.to_s
=> “123456789123456789”

irb(main):002:0> “#{s[0,2]}-#{s[2,4]}-#{s[6,4]}-#{s[10,4]}-#{s[14,4]}”
=> “12-3456-7891-2345-6789”

irb(main):003:0>
“#{s[0…1]}-#{s[2…5]}-#{s[6…9]}-#{s[10…13]}-#{s[14…17]}”
=> “12-3456-7891-2345-6789”

irb(main):004:0> def f(n, p=4, s="")
irb(main):005:1> i= n.to_i
irb(main):006:1> return s if i<=0
irb(main):007:1> a= 10**p
irb(main):008:1> f(i/a, p, (i%a).to_s+(s=="" ? “” : “-”+s))
irb(main):009:1> end
=> nil

irb(main):010:0> f s
=> “12-3456-7891-2345-6789”

irb(main):011:0> f s.to_i
=> “12-3456-7891-2345-6789”

irb(main):012:0> f s, 5
=> “123-45678-91234-56789”

On Jun 28, 2006, at 1:13 PM, Martin J. wrote:

=> nil

irb(main):010:0> f s
=> “12-3456-7891-2345-6789”

irb(main):011:0> f s.to_i
=> “12-3456-7891-2345-6789”

irb(main):012:0> f s, 5
=> “123-45678-91234-56789”

building on the ActionPack helper number_with_delimiters

def number_with_dashes(number, groups=4, delimiter="-")
re = %r/(\d)(?=(\d{#{groups}})+(?!\d))/
number.to_s.gsub(re, “\1#{delimiter}”)
end

irb(main):023:0> number_with_dashes(123456789123456789)
=> “12-3456-7891-2345-6789”

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.