Question: I need a regex statement that will check for three capital letters in a row.

For example, it should match: ABC, aABC, abcABC

But it should not match: AaBbBc, ABCDE

At the moment this is my statement:

```
'[^A-Z]*[A-Z]{3}[^A-Z]*'

```

But this matches ABCDE. What am I doing wrong?

Answer: 
Regex
-----

```
(?<![A-Z])[A-Z]{3}(?![A-Z])

```

Explanation
-----------

I specified a *negative lookbehind* and a *negative lookahead* before and after the middle regex for three capitals in a row, respectively.

This is a better option compared to using a negated character class because it will successfully match even when there are no characters to the left or right of the string.

Online Demonstration
--------------------

[**DEMO**](https://regex101.com/r/rI1tY6/1)

---

As for the Python code, I haven't figured out how to print out the actual matches, but this is the syntax:

Using `re.match`:

```
>>> import re
>>> p = re.compile(r'(?<![A-Z])[A-Z]{3}(?![A-Z])')
>>> s = '''ABC
... aABC
... abcABCabcABCDabcABCDEDEDEDa
... ABCDE'''
>>> result = p.match(s)
>>> result.group()
'ABC'

```

Using `re.search`:

```
>>> import re
>>> p = re.compile(r'(?<![A-Z])[A-Z]{3}(?![A-Z])')
>>> s = 'ABcABCde'
>>> p.search(s).group()
'ABC'

```
In your regular expression, the `[^A-Z]*` at the beginning and end is saying *"Look for any number of non-capital letters, including 0."* And so, `ABCDE` will satisfy your regular expression. For example, `A` can be seen as "0 non-capital letters" followed by `BCD` followed by `E`, which is also "0 non-capital letters."

I think what you want to do instead is craft a regular expression that looks for:

1. Either "a non-capital letter" **or** the start of my string.
2. Followed by "exactly 3 capital letters."
3. Followed by "a non-capital letter" **or** the end of my string.

It doesn't matter *how many* non-capital letters precede or follow your 3 capital letters, as long as there is at least 1. So, you just need to look for 1.

Try this:

```none
(^|[^A-Z])[A-Z]{3}([^A-Z]|$)

```

Note that the first `^` means start of string, which is different from the meaning of `^` inside the brackets. The `$` means end of string.

Tested in ruby, here is what we have:

```none
regexp = /(^|[^A-Z])[A-Z]{3}([^A-Z]|$)/
'ABC'.match(regexp)    # returns a match
'aABC'.match(regexp)   # returns a match
'abcABC'.match(regexp)  # returns a match
'AaBbBc'.match(regexp) # returns nil
'ABCDE'.match(regexp)  # returns nil

```