Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regex with limited use of specific characters (like a scrabble bank of letters)

I would like to be able to do a regex where I can identify sort of a bank of letters like [dgos] for example and use that within my regex... but whenever a letter from that gets used, it takes it away from the bank.

So lets say that somehow \1 is able to stand for that bank of letters (dgos). I could write a regex something like:

^\1{1}o\1{2}$

and it would match basically:
\1{1} = [dgos]{1}
o
\1{2} = [dgos]{2} minus whatever was used in the first one

Matches could include good, dosg, sogd, etc... and would not include sods (because s would have to be used twice) or sooo (because the o would have to be used twice).

I would also like to be able to identify letters that can be used more than once. I started to write this myself but then realized I didn't even know where to begin with this so I've also searched around and haven't found a very elegant way to do this, or a way to do it that would be flexible enough that the regex could easily be generated with minimal input.

I have a solution below using a combination of conditions and multiple regexs (feel free to comment thoughts on that answer - perhaps it's the way I'll have to do it?), but I would prefer a single regex solution if possible... and something more elegant and efficient if possible.

Note that the higher level of elegance and single regex part are just my preferences, the most important thing is that it works and the performance is good enough.

like image 232
Dallas Avatar asked Jul 22 '13 15:07

Dallas


1 Answers

Assuming you are using javascript version 1.5+ (so you can use lookaheads), here is my solution:

^([dogs])(?!.*\1)([dogs])(?!.*\2)([dogs])(?!.*\3)[dogs]$

So after each letter is matched, you perform a negative lookahead to ensure that this matched letter never appears again.

This method wouldn't work (or at least, would need to be made a heck of a lot more complicated!) if you want to allow some letters to be repeated, however. (E.g. if your letters to match are "example".)

EDIT: I just had a little re-think, and here is a much more elegant solution:

^(?:([dogs])(?!.*\1)){4}
like image 97
Tom Lord Avatar answered Nov 09 '22 00:11

Tom Lord