Regex: how to find 3 or more matches in a row NOT ONLY one by one

Viewed 111

I try to find rows in my file where '1/1' or '0/0' occur 3 or more times. I use regex in Python. I test my regex with https://regex101.com/.

Here is the part of my input file:

0   chr1  1152 NaN   G   A   1355.64     NaN   1/1   0/1   0/1  0/1   1/1   0/1   0/1   0/1   0/1   1/1   0/1   0/1
4   chr1  1331 NaN   A   C   4171.07     NaN   0/0   0/1   0/1  0/1   0/0   0/1   0/1   0/1   0/1   0/0   0/1   0/1
5   chr1  1349 NaN   T   C  11194.50     NaN   0/1   0/1   0/1  0/1   1/1   0/1   0/1   0/1   0/1   1/1   0/1   0/1
6   chr1  1401 NaN   T   G  10825.80     NaN   0/1   0/1   0/1  0/1   1/1   0/1   0/1   0/1   0/1   1/1   0/1   0/1
8   chr1  4045 NaN   G   T   1917.92     NaN   1/1   1/1   1/1  1/1   1/1   1/1   0/1   1/1   0/1   1/1   0/1   1/1

I wrote a regex to find the beginning of the line:

r"^\d\s{3}(chr\d)?\s{2}\d+\s+\D+\d+\.\d+\s+\w+"

but I have a problem with the next part. I've tried:

r"^\d\s{3}(chr\d)?\s{2}\d+\s+\D+\d+\.\d+\s+\w+(\s{2,}1/1|\s{2,}0/0)"

but it finds just the first occurrence of '1/1' or '0/0'. When I try to use:

r"^\d\s{3}(chr\d)?\s{2}\d+\s+\D+\d+\.\d+\s+\w+((\s{2,}1/1){3,}|(\s{2,}0/0){3,})"

then there is just one match where '1/1' occurs three times or more but one by one:

8   chr1  4045 NaN   G   T   1917.92     NaN   1/1   1/1   1/1  1/1   1/1   1/1   0/1   1/1   0/1   1/1   0/1   1/1

Any ideas on how to find all rows with >= 3 '1/1' or '0/0'? Thanks a lot!

3 Answers

If you want to keep the first capture group, you can use your first pattern, followed by matching 3 times either 0/0 or 1/1

^\d\s{3}(chr\d)\s{2}\d+\s+\D+\d+\.\d+\s+\w+(?:(?:\s{2,}\d/\d)*?\s{2,}([10])/\2\b){3}

The second part of the pattern:

(?:(?:\s{2,}\d/\d)*\s{2,}([10])/\2){3}
  • (?: Non capture group to repeat as a whole
    • (?: Non capture
      • \s{2,}\d/\d Match 2 or more whitespace chars
    • )*? Close group and optionally repeat non greedy
    • \s{2,} Match 2 or more whitespace chara
    • ([10])/\2\b Capture either 0 or 1 in group 2, and match / followed by a backreference to group 2 to match up the digits for 0/0 and 1/ followed by a word boundary to prevent a partial match
  • ){3} Close group and repeat 3 times

Regex demo

If you also want to match the rest of the line, you can append .* to the pattern.

Maybe you could use a positive lookahead:

^\d\s{3}(chr\d){2}\d+ +\D+\d+\.\d+\s+\w+(?=.*(([10])/\3)(?:.*\2){2})(?:\s+[10]/[10]){12}$

See an online demo

The added part (?=.*(([10])/\3)(?:.*\2){2})(?:\s+[10]/[10]){12}$ means:

  • (?= - Open a positive lookahead;
    • .* - Match 0+ (Greedy) characters other than newline;
    • (([10])/\3) - A 2st capture group to catch either a 1 or 0 that repeats itself after the forward slash;
    • (?:.*\2){2} - Open a non-capture group to match 0+ characters upto the pattern captured in the 2nd capture group and match two times;
    • ) - Close positive lookahead;
  • (?:\s+[10]/[10]){12} - A 2nd non-capture group to match 1+ whitespace characters and the pattern of 1s and 0s with the forward slash as delimiter. Match this group twelve times;
  • $ - End-line anchor.

This will work :

If 0/0 appears more than 3 times for any line :

(.*(?:0\/0\b).*){3}

If 1/1 appears more than 3 times for any line :

(.*(?:1\/1\b).*){3}

If 0/0 appears 3 times or 1/1 appears 3 times

(.*(?:1\/1\b).*){3}|(.*(?:0\/0\b).*){3}

If any of 0/0 1/1 appears 3 times

(.*(?:1\/1\b).*){3}|(.*(?:0\/0\b).*){3}|(.*((?:0\/0\b)|(?:1\/1)).*){3}

0/0 : enter image description here

1/1 : enter image description here

If 0/0 appears 3 times or 1/1 appears 3 times enter image description here

If any of 0/0 1/1 appears 3 times If any of 0/0 1/1 appears 3 times

Related