13

I am implementing the following problem in ruby.

Here's the pattern that I want :

1234, 1324, 1432, 1423, 2341 and so on

i.e. the digits in the four digit number should be between [1-4] and should also be non-repetitive.

to make you understand in a simple manner I take a two digit pattern and the solution should be : 12, 21

i.e. the digits should be either 1 or 2 and should be non-repetitive.

To make sure that they are non-repetitive I want to use $1 for the condition for my second digit but its not working.

Please help me out and thanks in advance.

Apoorv Saxena
  • 4,086
  • 10
  • 30
  • 46

4 Answers4

26

You can use this (see on rubular.com):

^(?=[1-4]{4}$)(?!.*(.).*\1).*$

The first assertion ensures that it's ^[1-4]{4}$, the second assertion is a negative lookahead that ensures that you can't match .*(.).*\1, i.e. a repeated character. The first assertion is "cheaper", so you want to do that first.

References

Related questions

Community
  • 1
  • 1
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
12

Just for a giggle, here's another option:

^(?:1()|2()|3()|4()){4}\1\2\3\4$

As each unique character is consumed, the capturing group following it captures an empty string. The backreferences also try to match empty strings, so if one of them doesn't succeed, it can only mean the associated group didn't participate in the match. And that will only happen if string contains at least one duplicate.

This behavior of empty capturing groups and backreferences is not officially supported in any regex flavor, so caveat emptor. But it works in most of them, including Ruby.

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
  • I copied and pasted this expression into http://gskinner.com/RegExr/ and tried the text 1244, and it matched it. It doesn't prevent duplicates. – gsgx Jun 22 '12 at 02:42
  • 4
    @gsingh2011: RegExr is a Flash app, which means it uses the ActionScript flavor. And ActionScript implements the ECMAScript standard, which decrees that a backreference to a group that hasn't yet participated in the match always succeeds, no matter what the group was supposed to match. See [here](http://blog.stevenlevithan.com/archives/fixing-javascript-regexp) for a discussion. This gimmick also doesn't work in JavaScript or VBScript, and it doesn't work in .NET if you specify the `ECMAScript` option, though it does otherwise. – Alan Moore Jun 22 '12 at 06:36
  • Thanks for the clarification. That's interesting. – gsgx Jun 22 '12 at 12:19
8

I think this solution is a bit simpler

^(?:([1-4])(?!.*\1)){4}$

See it here on Rubular

^                  # matches the start of the string
    (?:            # open a non capturing group 
        ([1-4])    # The characters that are allowed the found char is captured in group 1
        (?!.*\1)   # That character is matched only if it does not occur once more
    ){4}           # Defines the amount of characters
$

(?!.*\1) is a lookahead assertion, to ensure the character is not repeated.

^ and $ are anchors to match the start and the end of the string.

stema
  • 90,351
  • 20
  • 107
  • 135
0

While the previous answers solve the problem, they aren't as generic as they could be, and don't allow for repetitions in the initial string. For example, {a,a,b,b,c,c}. After asking a similar question on Perl Monks, the following solution was given by Eily:

^(?:(?!\1)a()|(?!\2)a()|(?!\3)b()|(?!\4)b()|(?!\5)c()|(?!\6)c()){6}$

Similarly, this works for longer "symbols" in a string, and for variable length symbols too.

Quantum Mechanic
  • 625
  • 1
  • 6
  • 20