2

Got a question regarding regex matching in Java. Given is a string with a defined length. Now I want to check with a matcher if every char contained in that String is different.

For example (only pass of length = 8):

String a = "abcdefgz" -> pass
String b = "aacdefgz" -> fail
String c = "abcdefghz" -> fail

So matching the length would simply be:

"^[a-zA-Z]{8}$"

But to get it working in combination with the condition that every contained char needs to be unique is quite tough.

  • 2
    Is using a regex a must? – toolkit Nov 06 '22 at 19:47
  • You can [capture](https://www.regular-expressions.info/brackets.html) each of the letters and check if [the same character](https://www.regular-expressions.info/backref.html) is not ahead by use of a lookahead: [`^(?:([a-zA-Z])(?!.*?\1)){8}$`](https://regex101.com/r/xKA84M/2) – bobble bubble Nov 06 '22 at 22:00

2 Answers2

1

Well, this one matches strings containing duplicates. This is basically the reverse of what you are looking for.

.*(.)+.*\1.*

If it's suitable, you can pick string that do not match this expression. Or maybe check regex negative match to improve it.

Vasily Liaskovsky
  • 2,248
  • 1
  • 17
  • 32
1

I have a very ugly way to do this using regex.

It uses named capture groups (?<name>), back references \k<name>, and negative lookahead assertions (?!).

@Test
public void testForNonRepeatedCharactersUsingRegex() {
    Pattern p = Pattern.compile("^(?<c1>[a-zA-Z])(?!.*\\k<c1>)" +
            "(?<c3>[a-zA-Z])(?!.*\\k<c3>)" +
            "(?<c2>[a-zA-Z])(?!.*\\k<c2>)" +
            "(?<c4>[a-zA-Z])(?!.*\\k<c4>)" +
            "(?<c5>[a-zA-Z])(?!.*\\k<c5>)" +
            "(?<c6>[a-zA-Z])(?!.*\\k<c6>)" +
            "(?<c7>[a-zA-Z])(?!.*\\k<c7>)" +
            ".$");
    Assertions.assertTrue(p.matcher("abcdefgh").matches());
    Assertions.assertTrue(p.matcher("ABCDEFGH").matches());
    Assertions.assertFalse(p.matcher("12345678").matches());
    Assertions.assertFalse(p.matcher("abefgh").matches());
    Assertions.assertFalse(p.matcher("").matches());
    Assertions.assertFalse(p.matcher("abcdefga").matches());
    Assertions.assertFalse(p.matcher("aaaabbbb").matches());
}

If you are able to not use regex, then a much cleaner, more legible solution is:

@Test
public void testForNonRepeatedCharactersUsingStreams() {
    Assertions.assertTrue(uniqueCharacterSequence("abcdefgh", 8));
    Assertions.assertTrue(uniqueCharacterSequence("ABCDEFGH", 8));
    Assertions.assertFalse(uniqueCharacterSequence("12345678", 8));
    Assertions.assertFalse(uniqueCharacterSequence("abefgh", 8));
    Assertions.assertFalse(uniqueCharacterSequence("", 8));
    Assertions.assertFalse(uniqueCharacterSequence("abcdefga", 8));
    Assertions.assertFalse(uniqueCharacterSequence("aaaabbbb", 8));
}

private static boolean uniqueCharacterSequence(String s, int length) {
    return  s.length() == length &&
            s.codePoints().allMatch(Character::isLetter) &&
            s.codePoints().distinct().count() == length;
}
toolkit
  • 49,809
  • 17
  • 109
  • 135