Forum: Ruby RegExp problem

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
42db98edb8de28e50395c4959a12a46a?d=identicon&s=25 Jf Rejza (manchoman)
on 2008-11-19 10:59
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.
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 Jesús Gabriel y Galán (Guest)
on 2008-11-19 11:21
(Received via mailing list)
On Wed, Nov 19, 2008 at 10:55 AM, Jf Rejza <jfferriere@gmail.com> 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.
D1f1c20467562fc1d8c8aa0d328def62?d=identicon&s=25 Florian Gilcher (skade)
on 2008-11-19 12:02
(Received via mailing list)
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 Gilcher
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 Jesús Gabriel y Galán (Guest)
on 2008-11-19 12:33
(Received via mailing list)
On Wed, Nov 19, 2008 at 11:58 AM, Florian Gilcher <flo@andersground.net>
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.
D1f1c20467562fc1d8c8aa0d328def62?d=identicon&s=25 Florian Gilcher (skade)
on 2008-11-19 13:05
(Received via mailing list)
> 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 Gilcher
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 Jesús Gabriel y Galán (Guest)
on 2008-11-19 14:23
(Received via mailing list)
On Wed, Nov 19, 2008 at 1:01 PM, Florian Gilcher <flo@andersground.net>
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.
851acbab08553d1f7aa3eecad17f6aa9?d=identicon&s=25 Ken Bloom (Guest)
on 2008-11-19 15:41
(Received via mailing list)
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
87349a7a95b3f2e83c20194ef122885c?d=identicon&s=25 Einar Magnús Boson (Guest)
on 2008-11-19 16:23
(Received via mailing list)
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
This topic is locked and can not be replied to.