RegExp problem


#1

Hy,

I would like to know how to extract a string delimited by too identical
characters from an another string(of any length).

ex string=“rzerze@foo@rezrzgrtez” how to get (or match) the foo string

thanks for your help.


#2

On Wed, Nov 19, 2008 at 10:55 AM, Jf Rejza removed_email_address@domain.invalid wrote:

Hy,

I would like to know how to extract a string delimited by too identical
characters from an another string(of any length).

ex string=“rzerze@foo@rezrzgrtez” how to get (or match) the foo string

irb(main):016:0> string=“rzerze@foo@rezrzgrtez”
=> “rzerze@foo@rezrzgrtez”
irb(main):017:0> (string.match /@(.*?)@/)[1]
=> “foo”

I don’t quite understand the rest of your requirement. You mean
delimited
by a string, i.e. the @ above is a variable, or by two of any character
present
in a string? If it’s the former:

irb(main):018:0> delimiter = “@”
=> “@”
irb(main):019:0> (string.match /#{delimiter}(.*?)#{delimiter}/)[1]
=> “foo”

if it’s the latter, something like this might help:

irb(main):024:0> re = Regexp.new("([#{delimiter}])(.)?\1")
=> /([@abcde])(.
)?\1/
irb(main):025:0> string.match(re)[2]
=> “rze@foo@rezrzgrt”

It found the first ‘e’ as the delimiter, don’t know why it took the
last ‘e’ as the other part of the delimiter, since I used a non-greedy
group for the middle part. Any ideas, someone?

Hope this helps,

Jesus.


#3

On Wed, Nov 19, 2008 at 11:58 AM, Florian G. removed_email_address@domain.invalid
wrote:

Actually the correct regexp is:

delimiter = Regexp.escape(delimiter)
/#{delimiter}[^#{delimiter}]*#{delimiter}/

Read: The delimiter - an unspecified number of non-delimiter-characters -
the delimiter.

Otherwise, you too heavily rely on the behaviour of the library, when it
coms to the dot.

Hi Florian,

I don’t get what you mean by “too heavily rely”, I mean, you are
always relying on the behaviour of the regexp library when it comes to
everything, so if you know how the dot, the * and the ? work in Ruby
why is your regexp better than the proposed one?

Anyway I have realized I had a mistake in my regexp (I had the ?
outside of the group, and not next to the *). So fixing that:

irb(main):034:0> string=“rzerze@foo@rezrzgrtez”
=> “rzerze@foo@rezrzgrtez”
irb(main):035:0> re = Regexp.new("([#{delimiter}])(.?)\1")
=> /([abcde])(.
?)\1/
irb(main):036:0> string.match(re)[2]
=> “rz”

Now works as I intended. With your version:

irb(main):037:0> re = /([#{delimiter}])([^#{delimiter}])\1/
=> /([abcde])([^abcde]
)\1/
irb(main):038:0> string.match(re)[2]
=> “rz”

works too. So I would like to know why would be one preferred over the
other.

Jesus.


#4

outside of the group, and not next to the ). So fixing that:
irb(main):037:0> re = /([#{delimiter}])([^#{delimiter}]
)\1/
=> /([abcde])([^abcde]*)\1/
irb(main):038:0> string.match(re)[2]
=> “rz”

works too. So I would like to know why would be one preferred over
the other.

Jesus.

Hi Jesus,

Because you could get problems when you have things like this:

“foo@fooo@bar@batz@foo”

you rely on the the behaviour of the dot. Meaning: yours matches

fooo@bar@batz

Thus, it ignores all inner delimiters.
In any case, mine matches:

[[“fooo”],[“batz”]] #String#scan output

Depending on how the dot is treated (greediness etc.), yours
could also have other interpretations (like mine) while mine is
clearer in
that respect.

In a simple case with only 2 delimiters, it doesn’t matter.

Actually, mine wasn’t correct either, i also forgot the brackets…

/#{delimiter}([^#{delimiter}])*#{delimiter}/

For more readibility, here is the version with delimiter = @:

/@([^@]*)@/

Regards,
Florian G.


#5

Actually the correct regexp is:

delimiter = Regexp.escape(delimiter)
/#{delimiter}[^#{delimiter}]*#{delimiter}/

Read: The delimiter - an unspecified number of non-delimiter-
characters - the delimiter.

Otherwise, you too heavily rely on the behaviour of the library, when
it coms to the dot.

Regards,
Florian G.


#6

On Wed, Nov 19, 2008 at 1:01 PM, Florian G. removed_email_address@domain.invalid
wrote:

Because you could get problems when you have things like this:

“foo@fooo@bar@batz@foo”

you rely on the the behaviour of the dot. Meaning: yours matches

fooo@bar@batz

Thus, it ignores all inner delimiters.

Well, with the correction, it doesn’t anymore:

irb(main):071:0>
“foo@fooo@bar@batz@foo”.match(/([#{delimiter}])(.*?)\1/)[2]
=> “fooo”

In any case, mine matches:

[[“fooo”],[“batz”]] #String#scan output

irb(main):072:0> “foo@fooo@bar@batz@foo”.scan(/([#{delimiter}])(.*?)\1/)
=> [["@", “fooo”], ["@", “batz”]]

Depending on how the dot is treated (greediness etc.), yours
could also have other interpretations (like mine) while mine is clearer in
that respect.

Well, obviously this only works as expected if you use the non-greedy
version.
But I understand what you mean about being clearer, more explicit.

In a simple case with only 2 delimiters, it doesn’t matter.

With more delimiters present in the string, mine works too.

Thanks,

Jesus.


#7

Now that we are on the topic of Regular Expressions I have a question
about the ruby implementation. Like I posted earlier I needed to parse
something that looks like this:

  • activity

    • name
    • picture
  • area

    • name
    • picture
  • activities_in_area

    • activity_id
    • area_id

etc…

Last time I did complicated regexps seems to have been C# or possibly
java. So I tried to match the whole thing with
/(- (\w*)\s*?\n([\t ]++ (\w+)\s*(:\s*(\w*))?\s*?\n)+\s*)+/
and then I was gonna extract the captured data but it isn’t available.
All nested groups have only captured their latest match. Is there no
regexp lib for ruby that can handle nested groups and save the
captures? I solved it with nested scans instead and I have to admin
that it is more readable, so I’m not sure what, exactly, I want with
this message, except ask about the design choices involved. Why don’t
we want proper captures?

table_name = /\- (\w*)\s*?\n/
field_name = /(\s+\+ (\w+)\s*(\:\s*(\w*))?\n)/
doc.scan /#{table_name}(#{field_name}+)/ do |tablename, fields|
  fields.scan field_name do |junk, fieldname, junk2, type|
    # here I can do what I want
  end
end

And on the topic of pattern matching, can you recommend any good
library for parser generation in ruby? I want to write a grammar and
get an AST.

einarmagnus


#8

On Wed, 19 Nov 2008 04:55:58 -0500, Jf Rejza wrote:

Hy,

I would like to know how to extract a string delimited by too identical
characters from an another string(of any length).

ex string=“rzerze@foo@rezrzgrtez” how to get (or match) the foo string

thanks for your help.

string.split(/@/)[1]

–Ken