Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby Regular expressions (regex): character appear only once at most

Tags:

regex

ruby

Suppose I want to make sure a string x equals any combination of abcd (each character appearing one or zero times-->each character should not repeat, but the combination may appear in any order)

  1. valid ex: bc .. abcd ... bcad ... b... d .. dc
  2. invalid ex. abcdd, cc, bbbb, abcde (ofcourse)

my effort: I tried various techniques: the closest I came was x =~ ^(((a)?(b)?(c)?(d)?))$

but this wont work if I do not type them in the same order as i have written:

  1. works for: ab, acd, abcd, a, d, c
  2. wont work for: bcda, cb, da (anything that is not in the above order)

you can test your solutions here : http://rubular.com/r/wCpD355bub

PS: the characters may not be in alphabetical order, it could be u c e t

like image 979
painterofthewind Avatar asked Dec 16 '22 10:12

painterofthewind


2 Answers

If you can use things besides regexes, you can try:

str.chars.uniq.length == str.length && str.match(/^[a-d]+$/)

The general idea here is that you just strip any duplicated characters from the string, and if the length of the uniq array is not equal to the length of the source string, you have a duplicated character in the string. The regex then enforces the character set.

This can probably be improved, but it's pretty straightforward. It does create a couple of extra arrays, so you might want a different approach if this needs to be used in a performance-critical location.

If you want to stick to regexes, you could use:

str.match(/^[a-d]+$/) && !str.match(/([a-d]).*\1/)

That'll basically check that the string only contains the allowed characters, and that those characters are never repeated.

like image 128
Chris Heald Avatar answered Jan 11 '23 23:01

Chris Heald


This is really not what regular expressions are meant to do, but if you really really want to.

Here is a regex that satisfies the conditions.

^([a-d])(?!(\1))([a-d])?(?!(\1|\3))([a-d])?(?!(\1|\3|\5))([a-d])?(?!(\1|\3|\5|\7))$

basically it goes through each character, making the group, then makes sure that that group isn't matched. Then checks the next character, and makes sure that group and the previous groups don't match.

like image 45
greedybuddha Avatar answered Jan 11 '23 23:01

greedybuddha