There seem to be several questions floating around Stackexchange regarding how to take a python regular expression list the matching instances. This problem is a bit different because 1) I'm need to start off with a domain-specific regex system, not just the standard python regex, and 2) the possible matches for any given location in string are limited to a specific 'alphabet' of characters.
The current implementation works, but I've got a nagging feeling there's a much more succinct way to do it.
import numpy as np
def shorthand_to_instances(shorthand,alphabet):
"""
Converts the shorthand-notation for bioinformatics 'motifs'
into the all the instances of sequences they would match.
Brackets means "it could be any of these letters" in this location.
Curly braces means "it's *not* one of these letters" in this location,
it can be any letter in the given "alphabet" except these.
Lowercase "x" means it could be any of the letters in the given
"alphabet".
>>> binf_motifs_to_sequences('T[AG]','AGCT')
['TA', 'TG']
>>> binf_motifs_to_sequences('T{A}T','AGCT')
['TGT', 'TCT', 'TTT']
>>> binf_motifs_to_sequences('G{AGC}AGTC','AGCT')
['GTAGTC']
>>> binf_motifs_to_sequences('xGTC','AGCT')
['AGTC', 'GGTC', 'CGTC', 'TGTC']
"""
instances=[]
shc = shorthand
while len(shc)>0:
char = shc[0]
assert char in alphabet+'['+']'+'{'+'}'+'x', "Failed assert: '{0}'".format(char)
if char in alphabet:
# it's in the alphabet
if len(instances)==0:
instances.append(char)
else:
for i in list(np.arange(len(instances))):
instances[i] += char
shc = shc[1:]
elif char=='[':
# it's a 'one of these'
chargroup,c,e = shc[1:].partition(']')
if len(instances)==0:
for char in chargroup:
instances.append(char)
else:
newinstances = []
for i in list(np.arange(len(instances))):
stem = instances[i]
for char in chargroup:
newinstances.append(stem+char)
instances = newinstances
shc = shc[len(chargroup)+2:]
elif char=='{':
# it's a 'not this / not these'
chargroup0,c,e = shc[1:].partition('}')
chargroup = alphabet.translate(None,chargroup0)
if len(instances)==0:
for char in chargroup:
instances.append(char)
else:
newinstances = []
for i in list(np.arange(len(instances))):
stem = instances[i]
for char in chargroup:
newinstances.append(stem+char)
instances = newinstances
shc = shc[len(chargroup0)+2:]
elif char=='x':
# it's an 'any char'
chargroup = alphabet
if len(instances)==0:
for char in chargroup:
instances.append(char)
else:
newinstances = []
for i in list(np.arange(len(instances))):
stem = instances[i]
for char in chargroup:
newinstances.append(stem+char)
instances = newinstances
shc = shc[1:]
else:
break
return instances
if __name__ == "__main__":
import doctest
doctest.testmod()