String.gsub with regex and block

  • Thread starter Alexey Petrushin
  • Start date
A

Alexey Petrushin

Probably a stupid question, but is there a way to use :gsub replacement
without $0 $1 $2 $3 (and without "\0\1\2\3")?

I would prefer something like:

"John Smith".gsub /(.+)\s(.+)/ do |name, family|
p [name, family]

# instead of this
p [$1, $2]
end
 
R

Reid Thompson

"John Smith".gsub /(.+)\s(.+)/ do |name, family|
p [name, family]

# instead of this
p [$1, $2]
end
is it a requirement that you use gsub?

irb(main):008:0> name, family = "John Smith".split
=> ["John", "Smith"]
irb(main):009:0> p [name, family]
["John", "Smith"]
=> nil
 
B

Brian Candler

Alexey Petrushin wrote in post #991484:
Probably a stupid question, but is there a way to use :gsub replacement
without $0 $1 $2 $3 (and without "\0\1\2\3")?

There is also $~ (Regexp.last_match); $1/$2/etc are just a facade.
I would prefer something like:

"John Smith".gsub /(.+)\s(.+)/ do |name, family|
p [name, family]

# instead of this
p [$1, $2]
end

"John Smith".gsub /(.+)\s(.+)/ do
name, family = $~.captures
p [name, family]
end

Not pretty, but you can wrap it up in your own method:

class String
def gsubcap(*arg)
gsub(*arg) { yield $~.captures }
end
end

"John Smith".gsubcap /(.+)\s(.+)/ do |name, family|
p [name, family]
end
 
B

Brian Candler

Or if you are a ruby 1.9 user, you could use named capture groups
instead. I'm not sure they make the regexp itself any clearer in this
case though:

"John Smith".gsub /(?<name>.+)\s(?<family>.+)/ do
p [$~[:name],$~[:family]]
end
 
7

7stud --

Alexey Petrushin wrote in post #991484:
Probably a stupid question, but is there a way to use :gsub replacement
without $0 $1 $2 $3 (and without "\0\1\2\3")?

Where are you replacing anything?
I would prefer something like:

"John Smith".gsub /(.+)\s(.+)/ do |name, family|
p [name, family]

# instead of this
p [$1, $2]
end


"John Smith".scan(/\S+/) do |match|
puts match
end

--output:--
John
Smith
 
7

7stud --

Brian Candler wrote in post #991490:
Alexey Petrushin wrote in post #991484:
Probably a stupid question, but is there a way to use :gsub replacement
without $0 $1 $2 $3 (and without "\0\1\2\3")?

There is also $~ (Regexp.last_match); $1/$2/etc are just a facade.
I would prefer something like:

"John Smith".gsub /(.+)\s(.+)/ do |name, family|
p [name, family]

# instead of this
p [$1, $2]
end

"John Smith".gsub /(.+)\s(.+)/ do
name, family = $~.captures
p [name, family]
end

And if you want to avoid writing code in perl:

str = "John Smith"
pattern = /(.+)\s(.+)/

result = str.gsub(pattern) do
md_obj = Regexp.last_match
first_name, last_name = md_obj[1], md_obj[2]

p first_name, last_name
end

Or to avoid any indexing, you could do this:

str = "John Smith"
pattern = /(.+)\s(.+)/

result = str.gsub(pattern) do |match|
first_name, last_name = match.split
p first_name, last_name

"some replacement"
end

puts result

--output:--
"John"
"Smith"
some replacement
 
P

Phillip Gawlowski

"John Smith".scan(/\S+/) do |match|
=A0puts match
end

irb(main):001:0> "John;Smith".scan /\S+/ do |match|
irb(main):002:1* puts match
irb(main):003:1> end
John;Smith
=3D> "John;Smith"

Ups.

Better:

irb(main):04:0> "John;Smith".scan /\w+/ do |match|
irb(main):05:1* puts match
irb(main):06:1> end
John
Smith

The code still makes assumptions about the data, though: it is uniform
in that only the first n parts are the name, and not n[+|-]1.

--=20
Phillip Gawlowski

Though the folk I have met,
(Ah, how soon!) they forget
When I've moved on to some other place,
There may be one or two,
When I've played and passed through,
Who'll remember my song or my face.
 
J

jake kaiden

Alexey Petrushin wrote in post #991484:
I would prefer something like:

"John Smith".gsub /(.+)\s(.+)/ do |name, family|
p [name, family]

# instead of this
p [$1, $2]
end

i also wonder if gsub is necessary... there's no replacement here as
far as i can tell. my oversimplified monkey brain comes up with this:


irb(main):001:0> str = "John Smith - Minister of Funny Walks."
=> "John Smith - Minister of Funny Walks."
irb(main):002:0> arr = str.split(" ")
=> ["John", "Smith", "-", "Minister", "of", "Funny", "Walks."]
irb(main):003:0> name, family = arr[0], arr[1]
=> ["John", "Smith"]
irb(main):004:0> puts name
John
=> nil
irb(main):005:0> puts family
Smith
=> nil

this also makes some assumptions about the data, of course...

-j
 
S

Sergey Avseyev

irb(main):001:0> str = "John Smith - Minister of Funny Walks."
=> "John Smith - Minister of Funny Walks."
irb(main):002:0> arr = str.split(" ")
=> ["John", "Smith", "-", "Minister", "of", "Funny", "Walks."]
irb(main):003:0> name, family = arr[0], arr[1]

name, family, = arr
 
B

Brian Candler

Chad Perrin wrote in post #991517:
. . . so, is there some way to use more descriptive variable names than
the default $1, $2, et cetera, for captures from within a regex? I'm
not
aware of any, but I too would find that agreeable.

Yes, ruby 1.9 has named capture groups. I posted an example earlier in
this thread.
 
A

Alexey Petrushin

Thanks for advices, I didn't know about $~ containting arrays of
results, add new 'substitute' method is probably the best solution.
This solution is not very generalizable. It only works as presented for
cases where all the stuff you want to discard looks the same.
No, it's no less generalizable than $X stuff, use splats if You have
different matches.
"John Smith".substitute{|*tokens| ...}

And yes the provided sample is unclear, there where actually no
replacement, maybe it should be something like that:

"John Smith".gsub /(.+)\s(.+)/ do |name, family|
"#{name[0..0]}. #{family}"
end


Here's the complete solution:

class String
def substitute(*args)
gsub(*args){yield Regexp.last_match.captures}
end

def substitute!(*args)
gsub!(*args){yield Regexp.last_match.captures}
end
end

Thanks for help!
 

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

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top