Regex of sequences surrounded by specific pattern with overlapping problem

Viewed 96

I am very new to use python re.finditer to find a regex pattern but trying to make a complex pattern finding, which is the g-quadruplex motif and described as below.

  1. The sequence starts with at least 3 g followed with a/t/g/c multiple times until the next group of ggg+ shows up. this will repeat 3 times and resulting in a pattern like ggg+...ggg+...ggg+...ggg+
  2. The cases should be all ignored and the overlapping can show in the original sequence like ggg+...ggg+...ggg+...ggg+...ggg+...ggg+ should return 3 such patterns.

I have suffered for some time and can only find a way like:

re.finditer(r"(?=(([Gg]{3,})([AaTtCcGg]+?(?=[Gg]{3,})[Gg]{3,}){3}))", seq) 

and then filter out the ones that do not with the same start position with

re.finditer(r"([Gg]{3,})", seq)

Is there any better way to extract this type of sequence? And no for loops please since I have millions of rows like this. Thank you very much!

PS: an example can be like this ggggggcgggggggACGCTCggctcAAGGGCTCCGGGCCCCgggggggACgcgcgAAGGGCTCC 1.ggggggcgggggggACGCTCggctcAAGGGCTCCGGG 2.gggggggACGCTCggctcAAGGGCTCCGGGCCCCggggggg 3.GGGCTCCGGGCCCCgggggggACgcgcgAAGGG

2 Answers

You could start the match, asserting that what is directly to the left is not a g char to prevent matching on too many positions.

To match both upper and lowercase chars, you can make the pattern case insensitive using re.I

The value is in capture group 1, which will be returned by re.findall.

(?<!g)(?=(g{3,}(?:[atc](?:g{0,2}[atc])*g{3,}){3}))
  • (?<!g) Negative lookbehind, assert not g directly to the left
  • (?= Positive lookahead
    • ( Capture group 1
      • g{3,} Match 3 or more g chars to start with
      • (?: Non capture group
        • [atc](?:g{0,2}[atc])* Optionally repeat matching a t c and 0, 1 or 2 g chars without crossing matching ggg
        • g{3,} Match 3 or more g chars to end with
      • ){3} Close non capture group and repeat 3 times
    • ) Close group 1
  • ) Close lookahead

Regex demo | Python demo

import re
 
pattern = r"(?<!g)(?=(g{3,}(?:[atc](?:g{0,2}[atc])*g{3,}){3}))"
s = ("ggggggcgggggggACGCTCggctcAAGGGCTCCGGGCCCCgggggggACgcgcgAAGGGCTCC \n")
print(re.findall(pattern, s, re.I))

Output

[
'ggggggcgggggggACGCTCggctcAAGGGCTCCGGG',
'gggggggACGCTCggctcAAGGGCTCCGGGCCCCggggggg',
'GGGCTCCGGGCCCCgggggggACgcgcgAAGGG'
]
import regex as re

seq = 'ggggggcgggggggACGCTCggctcAAGGGCTCCGGGCCCCgggggggACgcgcgAAGGGCTCC'

for match in re.finditer(r'(?<=(^|[^g]))g{3,}([atc](g{,2}[atc]+)*g{3,}){3}', seq, overlapped=True, flags=re.I):
    print(match[0])

Overlapped works by restarting the search from the character after the start of the current match rather than the end of it. This would give you a bunch of essentially duplicate results, each just removing an extra leading G. To stop that, check for a preceding G with a lookbehind:

(?<=(^|[^g]))

The middle section needs to be a bit more complicated to require an ATC, preventing the seven G's from being split into a ggggggg match. So require one, then allow for any number of less the three G's followed by more ATCs; repeating as needed:

[atc](g{,2}[atc]+)*

The rest is just the Gs and the repeating.

Related