[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Regular expression

Harry Kakueki

5/29/2009 8:30:00 AM

I want to write a regular expression to do the following.

The first character can be any character.
The second character can be anything except the first character.
The third character can be anything except the first two characters.
(This is a problem. There may be other problems.)
The fourth character is the same as the second character.

st = "abcb"
p st =~ /^(.)([^\1])([^\1\2])(\2)$/ # I expected a match

uv = "abbb"
p uv =~ /^(.)([^\1])([^\1\2])(\2)$/ # I did not expect a match


They both match.
How can I write the regular expression?
Somehow I have the syntax wrong.



Harry

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

12 Answers

Brian Candler

5/29/2009 8:49:00 AM

0

Harry Kakueki wrote:
> Somehow I have the syntax wrong.

Yes - I don't think a backreference like \1, which could contain any
number of characters, is usable inside a character class [...], which is
a list of individual characters.

irb(main):005:0> /[^\1]/ =~ "a"
=> 0
irb(main):006:0> /[^\1]/ =~ "1"
=> 0
irb(main):007:0> /[^\1]/ =~ "\001"
=> nil

So it seems that [^\1\2] means any character apart from \001 (ctrl-A) or
\002 (ctrl-B)

I think you need a negative lookahead assertion.
* http://www.ruby-doc.org/docs/Progra...
* click on "The Ruby Language"
* scroll to "Extensions"
* look for (?!re)

irb(main):009:0> /^(.)(?!\1)(.)(?!\1|\2)(.)(\2)$/ =~ "abcb"
=> 0
irb(main):010:0> /^(.)(?!\1)(.)(?!\1|\2)(.)(\2)$/ =~ "abbb"
=> nil
--
Posted via http://www.ruby-....

Robert Klemme

5/29/2009 9:50:00 AM

0

2009/5/29 Harry Kakueki <list.push@gmail.com>:
> I want to write a regular expression to do the following.
>
> The first character can be any character.
> The second character can be anything except the first character.
> The third character can be anything except the first two characters.
> (This is a problem. There may be other problems.)
> The fourth character is the same as the second character.
>
> st =3D "abcb"
> p st =3D~ /^(.)([^\1])([^\1\2])(\2)$/ =A0# I expected a match
>
> uv =3D "abbb"
> p uv =3D~ /^(.)([^\1])([^\1\2])(\2)$/ =A0# I did not expect a match
>
>
> They both match.
> How can I write the regular expression?
> Somehow I have the syntax wrong.

I second Brian: to solve this with a regular expression is either
extremely costly (large expression) or even impossible. If I
understand you properly then you want to avoid repetitions. How
about:

require 'set'
def unique_chars(s)
chars =3D s.scan /./
chars.to_set.size =3D=3D chars.size
end

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestprac...

Harry Kakueki

5/29/2009 10:51:00 AM

0

On Fri, May 29, 2009 at 6:49 PM, Robert Klemme
<shortcutter@googlemail.com> wrote:
> 2009/5/29 Harry Kakueki <list.push@gmail.com>:
>> I want to write a regular expression to do the following.
>>
>> The first character can be any character.
>> The second character can be anything except the first character.
>> The third character can be anything except the first two characters.
>> (This is a problem. There may be other problems.)
>> The fourth character is the same as the second character.
>>
>> st = "abcb"
>> p st =~ /^(.)([^\1])([^\1\2])(\2)$/ # I expected a match
>>
>> uv = "abbb"
>> p uv =~ /^(.)([^\1])([^\1\2])(\2)$/ # I did not expect a match
>>
>>
>> They both match.
>> How can I write the regular expression?
>> Somehow I have the syntax wrong.
>
> I second Brian: to solve this with a regular expression is either
> extremely costly (large expression) or even impossible. If I
> understand you properly then you want to avoid repetitions. How
> about:
>
> require 'set'
> def unique_chars(s)
> chars = s.scan /./
> chars.to_set.size == chars.size
> end
>
> Kind regards
>
> robert
>
> --
> remember.guy do |as, often| as.you_can - without end
> http://blog.rubybestprac...
>
>

Thanks, Robert.

Sometimes I want to avoid repetition and sometimes I want to have repetition.
My goal here is not just to solve such a problem.
My goal is to learn how to write this type of regular expression using
\1, \2, etc.
I did not understand the syntax.

Thanks,

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

Harry Kakueki

5/29/2009 11:12:00 AM

0

On Fri, May 29, 2009 at 5:48 PM, Brian Candler <b.candler@pobox.com> wrote:
> Harry Kakueki wrote:
>> Somehow I have the syntax wrong.
>
> Yes - I don't think a backreference like \1, which could contain any
> number of characters, is usable inside a character class [...], which is
> a list of individual characters.
>
> irb(main):005:0> /[^\1]/ =~ "a"
> => 0
> irb(main):006:0> /[^\1]/ =~ "1"
> => 0
> irb(main):007:0> /[^\1]/ =~ "\001"
> => nil
>
> So it seems that [^\1\2] means any character apart from \001 (ctrl-A) or
> \002 (ctrl-B)
>
> I think you need a negative lookahead assertion.
> * http://www.ruby-doc.org/docs/Progra...
> * click on "The Ruby Language"
> * scroll to "Extensions"
> * look for (?!re)
>
> irb(main):009:0> /^(.)(?!\1)(.)(?!\1|\2)(.)(\2)$/ =~ "abcb"
> => 0
> irb(main):010:0> /^(.)(?!\1)(.)(?!\1|\2)(.)(\2)$/ =~ "abbb"
> => nil
> --
> Posted via http://www.ruby-....
>
>

Brian,

I need to read that section carefully to be sure I understand.
But, I think that does the trick.

Thank you!

Harry

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

Robert Klemme

5/29/2009 11:55:00 AM

0

2009/5/29 Harry Kakueki <list.push@gmail.com>:
> On Fri, May 29, 2009 at 5:48 PM, Brian Candler <b.candler@pobox.com> wrote:

>> I think you need a negative lookahead assertion.
>> * http://www.ruby-doc.org/docs/Progra...
>> * click on "The Ruby Language"
>> * scroll to "Extensions"
>> * look for (?!re)
>>
>> irb(main):009:0> /^(.)(?!\1)(.)(?!\1|\2)(.)(\2)$/ =~ "abcb"
>> => 0
>> irb(main):010:0> /^(.)(?!\1)(.)(?!\1|\2)(.)(\2)$/ =~ "abbb"
>> => nil

> I need to read that section carefully to be sure I understand.
> But, I think that does the trick.

The problem with this approach is that it does not work for strings of
arbitrary length. Even if you adjust it to work for multiple lengths
you always have a fixed upper limit for which it can work.

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestprac...

Brian Candler

5/29/2009 12:20:00 PM

0

Robert Klemme wrote:
>>> irb(main):009:0> /^(.)(?!\1)(.)(?!\1|\2)(.)(\2)$/ =~ "abcb"
>>> => 0
>>> irb(main):010:0> /^(.)(?!\1)(.)(?!\1|\2)(.)(\2)$/ =~ "abbb"
>>> => nil
>
> The problem with this approach is that it does not work for strings of
> arbitrary length. Even if you adjust it to work for multiple lengths
> you always have a fixed upper limit for which it can work.

The OP explicitly said that he wanted to match single characters. It
would also make sense for other fixed-width fields, or delimited fields.

With neither fixed sizes nor delimiters, I don't think it makes any
sense. It would become "match any sequence of characters, followed by
any sequence of characters which isn't the same as the first sequence of
characters, followed by any sequence of characters which isn't the first
or second, followed by the second sequence of characters". And there
would be a squillion different ways to try and slice the string to make
it match.
--
Posted via http://www.ruby-....

Robert Klemme

5/29/2009 12:32:00 PM

0

2009/5/29 Brian Candler <b.candler@pobox.com>:
> Robert Klemme wrote:
>>>> irb(main):009:0> /^(.)(?!\1)(.)(?!\1|\2)(.)(\2)$/ =3D~ "abcb"
>>>> =3D> 0
>>>> irb(main):010:0> /^(.)(?!\1)(.)(?!\1|\2)(.)(\2)$/ =3D~ "abbb"
>>>> =3D> nil
>>
>> The problem with this approach is that it does not work for strings of
>> arbitrary length. =A0Even if you adjust it to work for multiple lengths
>> you always have a fixed upper limit for which it can work.
>
> The OP explicitly said that he wanted to match single characters. It
> would also make sense for other fixed-width fields, or delimited fields.

But he did not state explicitly that the _strings_ that he wanted to
analyze have fixed length. This is where your approach breaks. If
his strings are always of maximum length four or he only needs to make
sure the four first characters do not repeat then it will work.
"Four" could easily be any number up to "nine" but even then naming of
groups might cause trouble; in any case the expression will soon look
ugly, especially if strings can be "up to N" characters long.

> With neither fixed sizes nor delimiters, I don't think it makes any
> sense. It would become "match any sequence of characters, followed by
> any sequence of characters which isn't the same as the first sequence of
> characters, followed by any sequence of characters which isn't the first
> or second, followed by the second sequence of characters". And there
> would be a squillion different ways to try and slice the string to make
> it match.

That's beyond the power of regular expressions.

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestprac...

Brian Candler

5/29/2009 2:19:00 PM

0

Robert Klemme wrote:
> 2009/5/29 Brian Candler <b.candler@pobox.com>:
>> The OP explicitly said that he wanted to match single characters. It
>> would also make sense for other fixed-width fields, or delimited fields.
>
> But he did not state explicitly that the _strings_ that he wanted to
> analyze have fixed length. This is where your approach breaks.

But he's not just looking for strings with non-repeating characters.
Note the rule that says the fourth character must be equal to the second
character. This is an application-specific rule; I don't think we can
logically extend that to guess what the rule for the fifth or subsequent
characters would be.

>> With neither fixed sizes nor delimiters, I don't think it makes any
>> sense. It would become "match any sequence of characters, followed by
>> any sequence of characters which isn't the same as the first sequence of
>> characters, followed by any sequence of characters which isn't the first
>> or second, followed by the second sequence of characters". And there
>> would be a squillion different ways to try and slice the string to make
>> it match.
>
> That's beyond the power of regular expressions.

It's perfectly possible to express it as a regular expression, but you
have to beware that there could be many ways for it to match, so you
might not get what you expect.

>> /^(.+)(?!\1)(.+)(?!\1|\2)(.+)(\2)$/.match("foowibbleboingwibble").to_a
=> ["foowibbleboingwibble", "foowibbl", "e", "boingwibbl", "e"]
>> /^(.+?)(?!\1)(.+?)(?!\1|\2)(.+?)(\2)$/.match("foowibbleboingwibble").to_a
=> ["foowibbleboingwibble", "foo", "wibble", "boing", "wibble"]
--
Posted via http://www.ruby-....

Robert Klemme

5/29/2009 3:41:00 PM

0

2009/5/29 Brian Candler <b.candler@pobox.com>:
> Robert Klemme wrote:
>> 2009/5/29 Brian Candler <b.candler@pobox.com>:
>>> The OP explicitly said that he wanted to match single characters. It
>>> would also make sense for other fixed-width fields, or delimited fields=

Mark Kremer

6/1/2009 7:52:00 AM

0

I'm not sure if you still want the regex, but following regex should do
the trick: ^(.{1})(?!\1)(.{1})(?!\1|\2).{1}\2$

Harry Kakueki wrote:
> I want to write a regular expression to do the following.
>
> The first character can be any character.
> The second character can be anything except the first character.
> The third character can be anything except the first two characters.
> (This is a problem. There may be other problems.)
> The fourth character is the same as the second character.
>
> st = "abcb"
> p st =~ /^(.)([^\1])([^\1\2])(\2)$/ # I expected a match
>
> uv = "abbb"
> p uv =~ /^(.)([^\1])([^\1\2])(\2)$/ # I did not expect a match
>
>
> They both match.
> How can I write the regular expression?
> Somehow I have the syntax wrong.
>
>
>
> Harry
>
>