How to mimic Perl's `s///' in Ruby?

Given Perl's

    $_ = "123 foo";

    s/^(\d+)\s+//;
    $pid = $1;

    print "$_\n$pid\n";

all I can come up with is

    line = "123 foo"

    pid = nil
    line.sub!(/^(\d+)\s+/) {pid = $1; ''}

    puts line, pid

Is there a better way perhaps?

···

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
                                _/ _/ _/
                               _/ _/_/_/
                          _/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'

I don't think I understand the question. Ruby supports replacement with and empty string and even $1, just like Perl.

line.sub!(/^((\d+)\s+/, "")
puts "#{line}\n#{$1}"

Hope that helps.

James Edward Gray II

···

On Feb 9, 2005, at 2:10 PM, Jos Backus wrote:

Given Perl's

    $_ = "123 foo";

    s/^(\d+)\s+//;
    $pid = $1;

    print "$_\n$pid\n";

all I can come up with is

    line = "123 foo"

    pid = nil
    line.sub!(/^(\d+)\s+/) {pid = $1; ''}

    puts line, pid

Is there a better way perhaps?

Jos Backus wrote:

Given Perl's

    $_ = "123 foo";

    s/^(\d+)\s+//;
    $pid = $1;

    print "$_\n$pid\n";

all I can come up with is

    line = "123 foo"

    pid = nil
    line.sub!(/^(\d+)\s+/) {pid = $1; ''}

    puts line, pid

Is there a better way perhaps?

Use split over a regex when you can:

pid, line = "123 foo".split

puts pid
puts line

Also keep in mind that 'pid' is currently still a string, not a number
(if that matters to you).

Regards,

Dan

Jos Backus wrote:

Given Perl's

    $_ = "123 foo";

    s/^(\d+)\s+//;
    $pid = $1;

    print "$_\n$pid\n";

all I can come up with is

    line = "123 foo"

    pid = nil
    line.sub!(/^(\d+)\s+/) {pid = $1; ''}

    puts line, pid

Closer to the original Perl:

   line = "123 foo"
   line.sub!(/^(\d+)\s+/, '')
   pid = $1
   puts line, pid

The Pickaxe doc for String#sub states the MatchData $-variables will be available using the block form of String#sub!, but it doesn't bother to remind you that they are available in the non-block form as well.

···

--
Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/&gt;

"Jos Backus" <jos@catnook.com> schrieb im Newsbeitrag news:20050209201021.GA47301@lizzy.catnook.com...

Given Perl's

   $_ = "123 foo";

   s/^(\d+)\s+//;
   $pid = $1;

   print "$_\n$pid\n";

all I can come up with is

   line = "123 foo"

   pid = nil
   line.sub!(/^(\d+)\s+/) {pid = $1; ''}

   puts line, pid

Is there a better way perhaps?

Others have shown ways to mimic Perl - even so far as to include the trailing semicolons. I don't know why you want to mimic Perl, but here's how I'd do it in Ruby:

if /^(\d+)\s+(.*)$/ =~ str
  pid, name = $1, $2
else
  # no match
end

Or, if you expect it to always match:

raise "String error: #{str}" unless /^(\d+)\s+(.*)$/ =~ str
pid, name = $1, $2

Kind regards

    robert

irb(main):001:0> $_='123 foo'
=> "123 foo"
irb(main):002:0> puts (sub(/(\d+)\s*/,'')),$1
foo
123
=> nil

···

On Thu, 10 Feb 2005, Jos Backus wrote:

Given Perl's

    $_ = "123 foo";

    s/^(\d+)\s+//;
    $pid = $1;

    print "$_\n$pid\n";

all I can come up with is

    line = "123 foo"

    pid = nil
    line.sub!(/^(\d+)\s+/) {pid = $1; ''}

    puts line, pid

Is there a better way perhaps?

--
Wybo

Even a little closer to the original perl...Though I am sure you are
not asking how to get ruby syntax closer to Perls :slight_smile:

alias :s :sub

$_ = "123 foo";

s /^(\d+)\s+/, '';
$pid = $1;

print "#$_\n#$pid\n";

-Tom

···

On Thu, 10 Feb 2005, Glenn Parker defenestrated me: > Jos Backus wrote:

>Given Perl's
>
> $_ = "123 foo";
>
> s/^(\d+)\s+//;
> $pid = $1;
>
> print "$_\n$pid\n";

Closer to the original Perl:

  line = "123 foo"
  line.sub!(/^(\d+)\s+/, '')
  pid = $1
  puts line, pid

--
+ http://www.tc.umn.edu/~enebo +---- mailto:enebo@acm.org ----+

Thomas E Enebo, Protagonist | "A word is worth a thousand |
                             > pictures" -Bruce Tognazzini |

Glenn Parker wrote:

Closer to the original Perl:

  line = "123 foo"
  line.sub!(/^(\d+)\s+/, '')
  pid = $1
  puts line, pid

line = "123 foo"
pid = line.slice!(/\d+/, 1).to_i
puts line, pid

..slice!() is the in-place version of that will delete the matched stuff as well as returning it. Note that you can use Regexps with and even =.

str = "hello world"
str[/.(.)/, 1] # => "e"
str[/\s(.+)/, 1] = "bar"
str # => "hello bar"

Duh, for some reason I didn't realize that $1 etc. are available _outside_ the
block in the first place as they are global.

Thanks for all your responses people, enlightening as always.

···

On Thu, Feb 10, 2005 at 05:52:34AM +0900, Glenn Parker wrote:

The Pickaxe doc for String#sub states the MatchData $-variables will be
available using the block form of String#sub!, but it doesn't bother to
remind you that they are available in the non-block form as well.

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
                                _/ _/ _/
                               _/ _/_/_/
                          _/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'

I don't think I understand the question. Ruby supports replacement
with and empty string and even $1, just like Perl.

Somehow I didn't realize the significance of the $ in $1.

line.sub!(/^((\d+)\s+/, "")
puts "#{line}\n#{$1}"

Hope that helps.

Sure does, thanks.

···

On Thu, Feb 10, 2005 at 05:25:52AM +0900, James Edward Gray II wrote:

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
                                _/ _/ _/
                               _/ _/_/_/
                          _/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'

raise "String error: #{str}" unless /^(\d+)\s+(.*)$/ =~ str
pid, name = $1, $2

One thing I've wondered about: is this thread safe? Is there a chance
that between the first and second statements something will change the
result of the global variables?

I tend to use the more verbose:
.. pid, name = str.match(/^(\d+)\s+(.*)$/).captures
or
.. pid, name = str.scan(/^(\d+)\s+(.*)$/).flatten

Cheers,
Assaph

[snip]

str = "hello world"
str[/.(.)/, 1] # => "e"
str[/\s(.+)/, 1] = "bar"
str # => "hello bar"

and

$1 # => "world"

Isn't it too bad a non-match raises an IndexError instead of returning nil?

irb(main):006:0> if str[/(hello)/, 1] = ""; puts "match", $1; end
match
hello
=> nil
irb(main):007:0> if str[/(hallo)/, 1] = ""; puts "match", $1; end
IndexError: regexp not matched
        from (irb):7:in `='
        from (irb):7
irb(main):008:0>

···

On Thu, Feb 10, 2005 at 06:25:06AM +0900, Florian Gross wrote:

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
                                _/ _/ _/
                               _/ _/_/_/
                          _/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'

Assaph Mehr wrote:

raise "String error: #{str}" unless /^(\d+)\s+(.*)$/ =~ str
pid, name = $1, $2

One thing I've wondered about: is this thread safe? Is there a chance
that between the first and second statements something will change the
result of the global variables?

They are thread-global variables. The same applies for $_.

I still prefer this form for complex matches, though:

if md = re.match(str) then
   capture1, capture2 = md.captures
   ...
end

Jos Backus wrote:

Duh, for some reason I didn't realize that $1 etc. are available _outside_ the
block in the first place as they are global.

Not truly global, but per-thread instead.

···

--
Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/&gt;

Jos Backus wrote:

Isn't it too bad a non-match raises an IndexError instead of returning nil?

irb(main):006:0> if str[/(hello)/, 1] = ""; puts "match", $1; end
match
hello
=> nil
irb(main):007:0> if str[/(hallo)/, 1] = ""; puts "match", $1; end
IndexError: regexp not matched
        from (irb):7:in `='
        from (irb):7
irb(main):008:0>

Not sure why you'd want to do that (.slice!() works better IMHO), but perhaps you can do it like this:

"hello"[/((?:hallo)?)/, 1] = ""

> One thing I've wondered about: is this thread safe? Is there a

chance

> that between the first and second statements something will change

the

> result of the global variables?

They are thread-global variables. The same applies for $_.

I still prefer this form for complex matches, though:

if md = re.match(str) then
   capture1, capture2 = md.captures
   ...
end

Nice, thanks.

Oops, you're right. Thanks Glenn.

···

On Thu, Feb 10, 2005 at 10:40:33AM +0900, Glenn Parker wrote:

Not truly global, but per-thread instead.

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
                                _/ _/ _/
                               _/ _/_/_/
                          _/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'

Yes, that works too. And I just tried the slice! version and it is more
elegant than the solution. Thanks Florian.

···

On Thu, Feb 10, 2005 at 09:05:05AM +0900, Florian Gross wrote:

Jos Backus wrote:
Not sure why you'd want to do that (.slice!() works better IMHO), but
perhaps you can do it like this:

"hello"[/((?:hallo)?)/, 1] = ""

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
                                _/ _/ _/
                               _/ _/_/_/
                          _/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'