A regex

Hi!

I have a string in the following form: 2006%2F10%2Fasdfasdf (or more
generic: any_characters+%2Fany_characters+%2Frest_of_it). I am
wondering if I can retrieve the groups 2006, 10, asdfasdf thru a regex
(I confess I couldn’t figure it out so far :frowning: ).

many thanks,

./alex

Alexandru P. wrote:

I have a string in the following form: 2006%2F10%2Fasdfasdf (or more
generic: any_characters+%2Fany_characters+%2Frest_of_it). I am
wondering if I can retrieve the groups 2006, 10, asdfasdf thru a regex

String#split would be easier than using a regex in this case:

irb(main):001:0> ‘2006%2F10%2Fasdfasdf’.split(’%2F’)
=> [“2006”, “10”, “asdfasdf”]

On 10/27/06, Chris G. [email protected] wrote:

Alexandru P. wrote:

I have a string in the following form: 2006%2F10%2Fasdfasdf (or more
generic: any_characters+%2Fany_characters+%2Frest_of_it). I am
wondering if I can retrieve the groups 2006, 10, asdfasdf thru a regex

String#split would be easier than using a regex in this case:

irb(main):001:0> ‘2006%2F10%2Fasdfasdf’.split(‘%2F’)
=> [“2006”, “10”, “asdfasdf”]

Thanks for all suggestions, but the requirement is to be done thru
regex only :-). I knew how to do it with split, but I need to do it
with regexps only.

./alex

.w( the_mindstorm )p.

Alexandru P. wrote:

Thanks for all suggestions, but the requirement is to be done thru
regex only :-). I knew how to do it with split, but I need to do it
with regexps only.

How about just:

irb(main):001:0> match = ‘2006%2F10%2Fasdfasdf’.match
/^(.)%2F(.)%2F(.*)$/
=> #MatchData:0x1cf404
irb(main):002:0> match[1]
=> “2006”
irb(main):003:0> match[2]
=> “10”
irb(main):004:0> match[3]
=> “asdfasdf”

Hi –

On Fri, 27 Oct 2006, Alexandru P. wrote:

Thanks for all suggestions, but the requirement is to be done thru
regex only :-). I knew how to do it with split, but I need to do it
with regexps only.

Regexes alone don’t do anything other than specify a pattern. You
need to use a regular expression in some operation (like split) to
get a result.

David

s = “2006%2F10%2Fasdfasdf”
year,month,other = URL.decode(s).split(///)

On 10/27/06, [email protected] [email protected] wrote:

String#split would be easier than using a regex in this case:
need to use a regular expression in some operation (like split) to
get a result.

Yes… use groupings, but what I wanted to get is not done through
string.split or something, but through string =~ /pattern/ and than
like in Perl whatever to have access to the groups through $1, $2,
etc.

./alex

.w( the_mindstorm )p.

On 27.10.2006 16:39, Chris G. wrote:

irb(main):002:0> match[1]
=> “2006”
irb(main):003:0> match[2]
=> “10”
irb(main):004:0> match[3]
=> “asdfasdf”

This has a potential for disastrous backtracking with large strings.
This one is better - if you can guarantee there there is no “%” besides
the one preceding the “2F”:

=> “2006%2F10%2Fasdfasdf”

s.match(/^([^%])%2F([^%])%2F(.*)$/).to_a
=> [“2006%2F10%2Fasdfasdf”, “2006”, “10”, “asdfasdf”]

Or maybe even

s.match(/^((?>[^%]))%2F((?>[^%]))%2F((?>.*))$/).to_a
=> [“2006%2F10%2Fasdfasdf”, “2006”, “10”, “asdfasdf”]

:slight_smile:

Kind regards

robert

On 10/27/06, Robert K. [email protected] wrote:

=> #MatchData:0x1cf404

Yep… this is the closest I got too :-).

./alex

.w( the_mindstorm )p.

Robert K. wrote:

This has a potential for disastrous backtracking with large strings.
This one is better - if you can guarantee there there is no “%” besides
the one preceding the “2F”:

=> “2006%2F10%2Fasdfasdf”

s.match(/^([^%])%2F([^%])%2F(.*)$/).to_a
=> [“2006%2F10%2Fasdfasdf”, “2006”, “10”, “asdfasdf”]

Or maybe even

s.match(/^((?>[^%]))%2F((?>[^%]))%2F((?>.*))$/).to_a
=> [“2006%2F10%2Fasdfasdf”, “2006”, “10”, “asdfasdf”]

I have a couple of questions about this; I’m always trying to further my
(currently basic) understanding of regular expressions.

  1. Why does my first regex have a potential for disastrous backtracking?
    (By disastrous I assume you mean inefficient and CPU-time-consuming,
    right?)

  2. What does the “?>” do in your second regex? I haven’t seen that
    before.

Thanks!

Alexandru P. wrote:

Thanks for all suggestions, but the requirement is to be done thru
regex only :-). I knew how to do it with split, but I need to do it
with regexps only.

I’m unclear on what your real requirements are, but here are some
possible alternatives:

s = “2006%2F10%2Fasdfasdf”
p s.scan( /.+?(?=%2F|$)/ ).map{ |v| v.gsub( ‘%2F’, ‘’ ) }
#=> [“2006”, “10”, “asdfasdf”]

p s.gsub( ‘%2F’, “\n” ).scan( /[^\n]+/ )
#=> [“2006”, “10”, “asdfasdf”]

p s.match( /^(.+?)%2F(.+?)%2F(.+?)$/ ).to_a
#=> [“2006%2F10%2Fasdfasdf”, “2006”, “10”, “asdfasdf”]

On 10/27/06, Alexandru P. [email protected]
wrote:


.w( the_mindstorm )p.

I am pretty sure I am missing something from your requirements…

“some character%2Fmore stuff%2Fthe
rest…”.match(/^(.?)%2F(.?)%2F(.*)$/)
puts $1
puts $2
puts $3

pth

On 27.10.2006 16:39, [email protected] wrote:

String#split would be easier than using a regex in this case:
need to use a regular expression in some operation (like split) to
get a result.

Actually the code you presented did not even use a RX. You used the
string form of split, didn’t you? :slight_smile:

Kind regards

robert

On 27.10.2006 17:15, Chris G. wrote:

s.match(/^((?>[^%]))%2F((?>[^%]))%2F((?>.*))$/).to_a
=> [“2006%2F10%2Fasdfasdf”, “2006”, “10”, “asdfasdf”]

I have a couple of questions about this; I’m always trying to further my
(currently basic) understanding of regular expressions.

If you are really interested in the matter I can recommend “Mastering
Regular Expressions”. Even I got valuable insights from it although I
would have regarded me “senior” with regard to RX. :slight_smile:

  1. Why does my first regex have a potential for disastrous backtracking?
    (By disastrous I assume you mean inefficient and CPU-time-consuming,
    right?)

Correct. The first “." will match greedily as far as it can which
means: to the end of the sequence. Then the RX engine (it is a NFA in
the case of Ruby) detects that it cannot get an overall match with that
because there is no “%2F” following. So it starts backing up by
stepping back one character and trying the “%2F” again etc. This will
go until the first group matches “2006%2F10”. Ah, now we can match the
first “%2F” in the pattern. Then comes the next greedy ".
” and the
game starts over again with that. Match to the end, then try to back
up. Eventually the engine will find out that with the first group
eating up the first “%2F” as well there is no overall match since in the
remaining portion there is no more “%2F”. Then backing up the first
group starts again until the first group’s match is reduced to “2006”.

  1. What does the “?>” do in your second regex? I haven’t seen that
    before.

That’s an atomic sub RX. Basically it will not give back any characters
that it has consumed. Using that in this example with “.*” will make
the overall match fail:

s.match(/^((?>.))%2F((?>.))%2F((?>.*))$/).to_a
=> []

Actually I believe atomic grouping is not needed in this case as the
[^%] cannot match past a “%” and so there is probably no potential for
backtracking. Benchmarking probably shows the whole picture. It is
definitively harmful with “.*” because then the backtracking (see above)
cannot start and there will be no overall match.

You can easily see the backtracking with a tool like “Regex Coach” with
which you can step graphically through the match.

Kind regards

robert

Alexandru P. wrote:

Thanks for all suggestions, but the requirement is to be done thru
regex only :-). I knew how to do it with split, but I need to do it
with regexps only.

That seems to be splitting hairs (no pun intended), since “split” uses
regular expressions to split with.

On 10/27/06, Robert K. [email protected] wrote:

would have regarded me “senior” with regard to RX. :slight_smile:
go until the first group matches “2006%2F10”. Ah, now we can match the
That’s an atomic sub RX. Basically it will not give back any characters
cannot start and there will be no overall match.

You can easily see the backtracking with a tool like “Regex Coach” with
which you can step graphically through the match.

Kind regards

    robert

I guess a simple
/(.?)%2F(.?)%2F(.*)/
will be save.
It was just the greediness which might be dangerous.

Cheers
Robert


The reasonable man adapts himself to the world; the unreasonable one
persists in trying to adapt the world to himself. Therefore all progress
depends on the unreasonable man.

  • George Bernard Shaw

On Fri, 27 Oct 2006 22:23:42 +0900
“Alexandru P.” [email protected] wrote:


.w( the_mindstorm )p.

``
[thomas@debian ~]% irb
irb(main):001:0> a=“2006%2F10%2Fasdfasdf”.split(‘%2F’)
=> [“2006”, “10”, “asdfasdf”]
irb(main):002:0>
‘’

– Thomas A.

Hi –

On Fri, 27 Oct 2006, Alexandru P. wrote:

Hi!

I have a string in the following form: 2006%2F10%2Fasdfasdf (or more
generic: any_characters+%2Fany_characters+%2Frest_of_it). I am
wondering if I can retrieve the groups 2006, 10, asdfasdf thru a regex
(I confess I couldn’t figure it out so far :frowning: ).

Try this:

str.split("%2F")

to get all the other stuff in an array.

David