4
$\begingroup$

I have a file with protein sequences, all on a single line, like this:

>Contig_1 1FFPMPQ*CCLFSSSYLPA*AIMVTGSCQTLVQDKV*CLASCHVMIPPCVFHPIYPLFTWSPLHPIISGCF*AVCMCSWIHALFVEIILSWSLSLPFTFEISSD>Contig_2 1FFPCHNSVVYFLLLICLLKPLWSQGVVRHWYRTRCDAWLAVML*YLHVSFIPSIHFLLGRLCTLLYLDVFELYACAAGFMPCLLR*FSLGHSLFLLPLKFPATVKFFSLLGQIMNNISLMNDLQTGEKLQETH*EVEDKSALLVSIIESRCCVTLQPQDFSN*HLGKL*KSVGQKLK*VNDQITY*

I want to print all sequences between an M residue and a * that are at least 6 residues long, and I would like the output like this:

>contig_1.1.1 
M.......*
>contig_1.1.2 
M........*
>contig_2.1.1 
M............*
>contig_2.1.2 
M......*

Where the first number after the underscore is the number found in as the first character of the sequence (it is the reading frame) and the second number is the sequence number. and the last number is the fragment number. So, since the 1st sequence starts with;

>Contig_1 1FFPMPQ

The name will be >Contig_1.1 and each fragment found will be >Contig_1.1.1, >Contig_1.1.2, ... , >Contig_1.1.N.

After implementing the suggestion in the answer below and escaping the * in my regular expression, my current code is:

import sys
import re

myprotein = ">Contig_1 1FFPMPQ*CCLFSSSYLPA*AIMVTGSCQTLVQDKV*CLASCHVMIPPCVFHPIYPLFTWSPLHPIISGCF*AVCMCSWIHALFVEIILSWSLSLPFTFEISSD>Contig_2 1FFPCHNSVVYFLLLICLLKPLWSQGVVRHWYRTRCDAWLAVML*YLHVSFIPSIHFLLGRLCTLLYLDVFELYACAAGFMPCLLR*FSLGHSLFLLPLKFPATVKFFSLLGQIMNNISLMNDLQTGEKLQETH*EVEDKSALLVSIIESRCCVTLQPQDFSN*HLGKL*KSVGQKLK*VNDQITY*"
# parse record
my_protein = []
for line in myprotein:
    if not line.startswith('>'):
        my_protein.append(line)
    else:
        header = line

# build sequence
my_pro = ''.join(my_protein)

# cleave sequence                                                                                                                                                                                                                                                        
peptides = re.findall(r'(M[A-Z]{6,}\*)', my_pro)

# build a formatted list
records = ["%sNo.%d\n%s\n" % (header, idx + 1, fragment) for idx, fragment in     enumerate(peptides)]

# print list
for record in records:
    sys.stdout.write("%s" % (record))

And it prints:

 >No.1
 MVTGSCQTLVQDKV*
 >No.2
 MIPPCVFHPIYPLFTWSPLHPIISGCF*
 >No.3
 MNNISLMNDLQTGEKLQETH*

How can I change this to get my desired output format?

$\endgroup$
  • $\begingroup$ re.findall('M[A-Z]{6,}*', seq) $\endgroup$ – heathobrien May 1 '18 at 15:01
  • 2
    $\begingroup$ My apologies. the back-slash in my code got stripped for some reason. Try re.findall('M[A-Z]{6,}\*', seq) $\endgroup$ – heathobrien May 1 '18 at 15:24
  • 4
    $\begingroup$ Hi and welcome to the site! When posting this sort of question, please always include the errors you get. Telling us "this doesn't work" is really not very helpful, it is always better to explain how it fails. $\endgroup$ – terdon May 1 '18 at 15:47
  • $\begingroup$ Sorry for posting like that I just update my question so it would be great if you could help. Thanks $\endgroup$ – Nadecho Holme Attaveesin May 1 '18 at 16:30
2
$\begingroup$

The * character has a special meaning in regular expressions, it means "0 or more". So when you write {6,}*, the regex engine tries to apply the "0 or more" to the {6,*} and gets confused:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/re.py", line 222, in findall
    return _compile(pattern, flags).findall(string)
  File "/usr/lib/python3.6/re.py", line 301, in _compile
    p = sre_compile.compile(pattern, flags)
  File "/usr/lib/python3.6/sre_compile.py", line 562, in compile
    p = sre_parse.parse(p, flags)
  File "/usr/lib/python3.6/sre_parse.py", line 855, in parse
    p = _parse_sub(source, pattern, flags & SRE_FLAG_VERBOSE, 0)
  File "/usr/lib/python3.6/sre_parse.py", line 416, in _parse_sub
    not nested and not items))
  File "/usr/lib/python3.6/sre_parse.py", line 619, in _parse
    source.tell() - here + len(this))
sre_constants.error: multiple repeat at position 10

In order to use special characters literally, as simple strings, you need to escape them by adding a \ before them. So try:

import re
myprotein = ">Contig_1 1FFPMPQ*CCLFSSSYLPA*AIMVTGSCQTLVQDKV*CLASCHVMIPPCVFHPIYPLFTWSPLHPIISGCF*AVCMCSWIHALFVEIILSWSLSLPFTFEISSD"
protein = re.findall('M[A-Z]{6,}\*',myprotein)
print(protein)
['MVTGSCQTLVQDKV*', 'MIPPCVFHPIYPLFTWSPLHPIISGCF*']

To get the output you asked for while reading from a file, you can do:

import sys
import re

proteinFile = sys.argv[1]

with open(proteinFile, 'r') as f:
    for line in f:
        ## Split the long input line into the list 'sequences'
        sequences = line.rstrip('\n').split('>')

        for i, k in list(enumerate(sequences)):
            ## Skip the first element which will be empty.
            ## there must be a pythonic way of doing this, but I'm
            ## a Perl hacker, so I don't know it.             
            if len(k) == 0:
                continue

            seqName, seq = k.split(' ')
            ## Get the frame
            frame = seq[0]
            ## Remove the frame from the sequence
            seq = seq[1:]
            # cleave sequence
            peptides = re.findall(r'(M[A-Z]{6,}\*)', seq)

            for idx, peptide in enumerate(peptides):
                print(">%s.%s.%d\n%s" % (seqName, frame, idx+1, peptide) )
| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.