No way of looking for a regrexp match starting from a particularpoint in a string?

  • Thread starter Kenneth McDonald
  • Start date
K

Kenneth McDonald

I'm probably just missing something obvious, but I haven't found a way
to match a regular expression against only part of a string, in
particular only past a certain point of a string, as a way of finding
successive matches. Of course, one could do a match against a string,
take the substring past that match and do a match against the substring,
and so on, to find all of the matches for the string, but that could be
very expensive for very large strings.

I'm aware of the String.scan method, but that doesn't work for me
because it doesn't return MatchData instances.

What I want is just something like regexp.match(string, n), where the
regexp starts looking for a match at or after position n in the string.


Thanks,
Ken
 
N

Nobuyoshi Nakada

Hi,

At Sun, 3 Jun 2007 12:59:24 +0900,
Kenneth McDonald wrote in [ruby-talk:254054]:
What I want is just something like regexp.match(string, n), where the
regexp starts looking for a match at or after position n in the string.

string.index(regexp, n)
 
H

Harry Kakueki

What I want is just something like regexp.match(string, n), where the
regexp starts looking for a match at or after position n in the string.


Thanks,
Ken

You could match the string but ignore the first part of the match.

str = "abcdefghabcehjjjuabcfjkiabcgdfg"
str =~ /(abc.)/
p $1 # abcd
str =~ /a.*ju(abc.)/
p $1 #abcf

Harry
 
P

Patrick Hurley

I'm probably just missing something obvious, but I haven't found a way
to match a regular expression against only part of a string, in
particular only past a certain point of a string, as a way of finding
successive matches. Of course, one could do a match against a string,
take the substring past that match and do a match against the substring,
and so on, to find all of the matches for the string, but that could be
very expensive for very large strings.

I'm aware of the String.scan method, but that doesn't work for me
because it doesn't return MatchData instances.

What I want is just something like regexp.match(string, n), where the
regexp starts looking for a match at or after position n in the string.


Thanks,
Ken

I don't know of anything obvious, but I would probably do something a
little more like:


class String
def match_each(exp)
str = self
while md = str.match(exp)
yield md
str = md.post_match
end
end
end

foo = "foo bar foo bar foo"
foo.match_each /[oa][or]/ do |md|
puts "Found: #{md}"
end

# pth
 
P

Patrick Hurley

Hi,

At Sun, 3 Jun 2007 12:59:24 +0900,
Kenneth McDonald wrote in [ruby-talk:254054]:
What I want is just something like regexp.match(string, n), where the
regexp starts looking for a match at or after position n in the string.

string.index(regexp, n)

I think he wanted MatchData objects. The String#index method returns
the index (numeric position of the match). But if all you want are
captures, then index is a good solution.

pth
 
E

Edwin Fine

Kenneth said:
I'm probably just missing something obvious, but I haven't found a way
to match a regular expression against only part of a string, in
particular only past a certain point of a string, as a way of finding
successive matches. Of course, one could do a match against a string,
take the substring past that match and do a match against the substring,
and so on, to find all of the matches for the string, but that could be
very expensive for very large strings.

I'm aware of the String.scan method, but that doesn't work for me
because it doesn't return MatchData instances.

What I want is just something like regexp.match(string, n), where the
regexp starts looking for a match at or after position n in the string.


Thanks,
Ken

How about this?

def match(s, re, n)
/(?:.{#{n}})(#{re})/.match(s)
end

irb(main):043:0> p s
"abdefgh abdefgh abdefgh abdefgh abdefgh abdefgh abdefgh abdefgh abdefgh
abdefgh "
irb(main):044:0> p match(s, /abd/, 10).begin(1)
16
irb(main):045:0> p match(s, /abd/, 20).begin(1)
24
 
H

Harry Kakueki

You could match the string but ignore the first part of the match.

str = "abcdefghabcehjjjuabcfjkiabcgdfg"
str =~ /(abc.)/
p $1 # abcd
str =~ /a.*ju(abc.)/
p $1 #abcf

Harry

If you want to specify the point in the string by number, you could do this.

str = "abcdefghabcehjjjuabcfjkiabcgdfg"
str =~ /.{10}(abc.).*(abc.)/
p $1 #abcf
p $2 #abcg

Harry
 
K

Kenneth McDonald

Edwin said:
How about this?

def match(s, re, n)
/(?:.{#{n}})(#{re})/.match(s)
end

irb(main):043:0> p s
"abdefgh abdefgh abdefgh abdefgh abdefgh abdefgh abdefgh abdefgh abdefgh
abdefgh "
irb(main):044:0> p match(s, /abd/, 10).begin(1)
16
irb(main):045:0> p match(s, /abd/, 20).begin(1)
24
That's clever. Obscure, but clever :). I wonder if the regexp engine is
clever enough to turn a match like .{n} into a constant time operation?

Thanks,
Ken
 
N

Nobuyoshi Nakada

Hi,

At Sun, 3 Jun 2007 13:56:05 +0900,
Patrick Hurley wrote in [ruby-talk:254059]:
I think he wanted MatchData objects. The String#index method returns
the index (numeric position of the match). But if all you want are
captures, then index is a good solution.

String#index also sets $~.
 
P

Patrick Hurley

Hi,

At Sun, 3 Jun 2007 13:56:05 +0900,
Patrick Hurley wrote in [ruby-talk:254059]:
I think he wanted MatchData objects. The String#index method returns
the index (numeric position of the match). But if all you want are
captures, then index is a good solution.

String#index also sets $~.

I should have know to never question Nobu Nakada :), I always forget
about those variables.

Thanks
pth
 
R

Robert Klemme

Hi,

At Sun, 3 Jun 2007 13:56:05 +0900,
Patrick Hurley wrote in [ruby-talk:254059]:
I think he wanted MatchData objects. The String#index method returns
the index (numeric position of the match). But if all you want are
captures, then index is a good solution.

String#index also sets $~.

But then you can also use String#scan:

irb(main):002:0> "ababb".scan(/(a)b+/) {p $~}
#<MatchData:0x7ff94618>
#<MatchData:0x7ff94578>
=> "ababb"
irb(main):003:0> "ababb".scan(/(a)b+/) {p $~.to_a}
["ab", "a"]
["abb", "a"]
=> "ababb"

Ken, why do you need MatchData objects?

Kind regards

robert
 
L

Logan Capaldo

I'm probably just missing something obvious, but I haven't found a way
to match a regular expression against only part of a string, in
particular only past a certain point of a string, as a way of finding
successive matches. Of course, one could do a match against a string,
take the substring past that match and do a match against the substring,
and so on, to find all of the matches for the string, but that could be
very expensive for very large strings.

I'm aware of the String.scan method, but that doesn't work for me
because it doesn't return MatchData instances.

What I want is just something like regexp.match(string, n), where the
regexp starts looking for a match at or after position n in the string.
require 'strscan'
scanner = StringScanner.new(string)
scanner.pos = n
if scanner.scan(regexp)
p scanner[1]
p scanner.matched
p scanner.pos
end

It's in the stdlib. (Note, it doesn't actually give you a match data, or
set $~, but of the top of my head I can't think of anything that a
matchdata can do that the stringscanner can't.)
 
R

Rick DeNatale

For that matter, so does String#scan.

Hence:
irb(main):001:0> "abcdefabc".scan(/abc/) {puts "#{$~.inspect}, #{$~}"}
#<MatchData:0xb7b0220c>, abc
#<MatchData:0xb7b021e4>, abc
=> "abcdefabc"
 
K

Kenneth McDonald

Is $~ thread safe?

To bad it has to be done this way (though my library will hide it). I
first looked at Ruby several years ago, and at that time, didn't go
further with it because it was too PERLish for me. (PERL was great for
its time, but speaking as someone who actually had to maintain a lot of
PERL code, it's actually a pretty grotty language). One of the things
that brought me back to Ruby was the fact that an effort was being made
to move Ruby away from its PERLisms. But I guess it'll take a while
longer...

Thanks everyone,
Ken
 
R

Robert Klemme

Is $~ thread safe?
Yes.

To bad it has to be done this way (though my library will hide it). I
first looked at Ruby several years ago, and at that time, didn't go
further with it because it was too PERLish for me. (PERL was great for
its time, but speaking as someone who actually had to maintain a lot of
PERL code, it's actually a pretty grotty language). One of the things
that brought me back to Ruby was the fact that an effort was being made
to move Ruby away from its PERLisms. But I guess it'll take a while
longer...

Thanks everyone,

Ken, I still don't understand why exactly you need MatchData objects.
What are you trying to achieve?

Kind regards

robert
 
R

Robert Dober

I'm probably just missing something obvious, but I haven't found a way
to match a regular expression against only part of a string, in
particular only past a certain point of a string, as a way of finding
successive matches. Of course, one could do a match against a string,
take the substring past that match and do a match against the substring,
and so on, to find all of the matches for the string, but that could be
very expensive for very large strings.

I'm aware of the String.scan method, but that doesn't work for me
because it doesn't return MatchData instances.

What I want is just something like regexp.match(string, n),
Hmm apart of using #scan and #index with $~ as indicated, I do not
think that there is a performance penalty if you do

rg.match(string[n..-1])

Cheers
Robert
 
T

Trans

On 6/3/07 said:
to match a regular expression against only part of a string, in
particular only past a certain point of a string, as a way of finding
successive matches. Of course, one could do a match against a string,
take the substring past that match and do a match against the substring,
and so on, to find all of the matches for the string, but that could be
very expensive for very large strings.
I'm aware of the String.scan method, but that doesn't work for me
because it doesn't return MatchData instances.
What I want is just something like regexp.match(string, n),

Hmm apart of using #scan and #index with $~ as indicated, I do not
think that there is a performance penalty if you do

rg.match(string[n..-1])

How can that be? You have to create a whole new String. If that can be
avoided in the internal implementation then adding an optional offset
index to #match is not an unreasonable idea.

T.
 

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,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top