Chris Claude
Chris Claude

Reputation: 1372

How do I use Regex to find a letter and its opposite case one following the other in a string?

How can I match all occurrences of "an Upper and Lower case" or vice versa of the same letter following each other in a string using regex? e.g: "aADFfGcCgs", I want to match aA, Ff and cC I am doing the following re.findall('[a-Z][A-Z]', string) which can only match two characters which are not necessarily the opposite case of the other letter.

Upvotes: 3

Views: 143

Answers (3)

Boseong Choi
Boseong Choi

Reputation: 2596

@Wiktor Stribiżew's answer is obviously the best.
But for just showing another method(without regex),
I append code for @FoolischEx's idea.

import itertools
from string import ascii_letters


def pairwise(iterable):
    """From Itertools Recipes
    https://docs.python.org/3/library/itertools.html#itertools-recipes
    """
    a, b = itertools.tee(iterable)
    next(b, None)
    return zip(a, b)


def find_all(string: str) -> list:
    return [
        ''.join((a, b)) for a, b in pairwise(string)
        if all((
            a in ascii_letters,
            b in ascii_letters,
            abs(ord(a) - ord(b)) == abs(ord('A') - ord('a')),
        ))
    ]


print(find_all('AaaAbBcDdD'))

output:

['Aa', 'aA', 'bB', 'Dd', 'dD']

Note that there is little difference between this and using regex.
regex output for same string:

['Aa', 'aA', 'bB', 'Dd']

Upvotes: 0

FoolischEx
FoolischEx

Reputation: 79

I dont think regex can check relations in patterns.

I would iterate through each char and see if the char is between 97 and 122 or 65 and 90 to see if the char is upper or lower and then check the neighboring char - or + 32.

Upvotes: 0

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626929

You may use

print( [x.group() for x in re.finditer(r'([a-zA-Z])(?!\1)(?i:\1)', 'aADFfGcCgs')] )
# => ['aA', 'Ff', 'cC']

With re.findall:

[x for x,y in re.findall(r'(([a-zA-Z])(?!\2)(?i:\2))', 'aADFfGcCgs')]

See the Python demo.

Details

  • ([a-zA-Z]) - Capturing group 1: an ASCII letter
  • (?!\1) - the next char should not equal the letter captured in Group 1
  • (?i:\1) - the same char as captured in Group 1, but the pattern can match in a case insensitive way.

Upvotes: 6

Related Questions