No way of looking for a regrexp match starting from a partic


#1

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


#2

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)


#3

On 6/3/07, Kenneth McDonald removed_email_address@domain.invalid wrote:

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

A Look into Japanese Ruby List in English
http://www.kakueki.com/


#4

On 6/2/07, Kenneth McDonald removed_email_address@domain.invalid wrote:

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


#5

On 6/3/07, Nobuyoshi N. removed_email_address@domain.invalid wrote:

Nobu Nakada

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


#6

On 6/3/07, Harry K. removed_email_address@domain.invalid wrote:

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

A Look into Japanese Ruby List in English
http://www.kakueki.com/


#7

Edwin F. wrote:

I’m aware of the String.scan method, but that doesn’t work for me
How about this?
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


#8

Hi,

At Sun, 3 Jun 2007 13:56:05 +0900,
Patrick H. 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 $~.


#9

Kenneth McDonald wrote:

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


#10

On 6/3/07, Nobuyoshi N. removed_email_address@domain.invalid wrote:


Nobu Nakada

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

Thanks
pth


#11

On 03.06.2007 07:30, Nobuyoshi N. wrote:

Hi,

At Sun, 3 Jun 2007 13:56:05 +0900,
Patrick H. 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


#12

On Sun, Jun 03, 2007 at 12:59:24PM +0900, Kenneth McDonald wrote:

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


#13

Nobuyoshi N. wrote:

String#index also sets $~.
For that matter, so does String#scan.


#14

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


#15

On 6/3/07, Devin M. removed_email_address@domain.invalid wrote:

Nobuyoshi N. wrote:

String#index also sets $~.
For that matter, so does String#scan.

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


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


#16

Kenneth McDonald wrote:

Is $~ thread safe?

Yes. All the regex match “global” variables are actually per-thread. See
p.319 of Pick Axe 2nd ed.


#17

On 04.06.2007 00:44, Kenneth McDonald wrote:

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


#18

On 6/3/07, Kenneth McDonald removed_email_address@domain.invalid wrote:

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


#19

On 6/4/07, Robert D. removed_email_address@domain.invalid wrote:

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

My bad how stupid, am I thinking in C???
Robert


#20

On 6/4/07, Trans removed_email_address@domain.invalid wrote:

How can that be? You have to create a whole new String.
Beating a dead man Tom? As mentioned I had a terrible slip to C in my
reasoning, no idea why :frowning: