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

J

Jos Backus

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'
 
J

James Edward Gray II

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?

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
 
D

Daniel Berger

Jos said:
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
 
G

Glenn Parker

Jos said:
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.
 
T

Thomas E Enebo

Closer to the original Perl:

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

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

alias :s :sub

$_ = "123 foo";

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

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

-Tom
 
F

Florian Gross

Glenn said:
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"
 
J

Jos Backus

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.

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.

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

Jos Backus

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.

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

Jos Backus

On Thu, Feb 10, 2005 at 06:25:06AM +0900, Florian Gross wrote:
[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>

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

Robert Klemme

Jos Backus said:
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
 
W

Wybo Dekker

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?

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

Assaph Mehr

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
 
F

Florian Gross

Jos said:
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] = ""
 
F

Florian Gross

Assaph said:
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
 
A

Assaph Mehr

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.
 
G

Glenn Parker

Jos said:
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.
 
J

Jos Backus

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] = ""

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

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

Jos Backus

Not truly global, but per-thread instead.

Oops, you're right. Thanks Glenn.

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

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top