import random

from collections import namedtuple

Rule = namedtuple('Rule', ['changes', 'environments'])

sonorization = Rule({'p': 'b', 't': 'd', 'ʈ': 'ɖ', 'c':'ɟ', 'k': 'g', 'q': 'ɢ'},
                    ['^.', 'V.V'])

rules = [sonorization]

words = ['potato', 'tobado', 'tabasco']

def choose_rule(words, rules):
    '''Returns a sound change rule from rules applicable to the given word list.'''
    filtered_rules = filter_rules_by_phonemes(words, rules)
    # filtered_rules = filter_rules_by_environments(words, filtered_rules)

    # selected_rule = random.choice(filtered_rules)

def intersecting(set_1, set_2):
    '''Return true if the intersection of the two sets isn't empty, false
otherwise.
    '''
    return (len(set_1.intersection(set_2)) != 0)

def filter_rules_by_phonemes(words, rules):
    '''Returns a list of rules which contain phonemes that are present in the given
word list.
    '''
    word_phonemes = set(''.join(words))

    return [rule for rule in rules if intersecting(word_phonemes,
                                                   set(rule.changes.keys()))]

def filter_rules_by_environments(words, rules):
    '''Returns a list of rules which apply to at least one word in the given word
list, taking into account the environments in which the rule applies.
    '''
    pass

if __name__ == '__main__':
    choose_rule(words, rules)

@@ -6,16 +6,26 @@
 t random
+%0Aimport re
 %0A%0Afrom c
@@ -223,20 +223,27 @@
 ', 'V.V'
+, '.$'
 %5D)%0A%0A
+%0A
 rules = 
@@ -272,14 +272,14 @@
 = %5B'
-p
 otato
+p
 ', '
@@ -288,16 +288,17 @@
 bado', '
+x
 tabasco'
@@ -478,18 +478,16 @@
 les)%0A   
- #
  filtere
@@ -549,16 +549,42 @@
 rules)%0A%0A
+    return filtered_rules%0A
     # se
@@ -914,16 +914,8 @@
 are 
-present 
 in t
@@ -926,14 +926,14 @@
 iven
-%0A
+ 
 word
- 
+%0A
 list
@@ -1128,16 +1128,198 @@
 s()))%5D%0A%0A
+%0Adef rule_phonemes(rule):%0A    '''Returns a set of the target phonemes of the rule, i.e. the phonemes used as%0Akeys in the changes dictionary.'''%0A    return set(rule.changes.keys())%0A%0A%0A
 def filt
@@ -1513,24 +1513,1086 @@
 ies.
-%0A    '''%0A    pas
+ The rules%0Ahave all extraneous phoneme pairs removed, for maximum efficiency.%0A    '''%0A    filtered_rules = %5B%5D%0A%0A    # Combine the word list into one string, separated by newlines, to speed up%0A    # regex search.%0A    combined_words = '%5Cn'.join(words)%0A%0A    for rule in rules:%0A        phonemes = ''.join(rule_phonemes(rule))%0A        applicable_environments = %5B%5D%0A%0A        for environment in rule.environments:%0A            # Get a set of target phonemes which appear in the environment.%0A            regex = environment.replace('.', '(%5B%7B0%7D%5D)'.format(phonemes))%0A            targets = set(re.findall(regex, combined_words, re.MULTILINE))%0A%0A            # If there are targets available, create a new rule with just those%0A            # targets and the current environment and add it to the filtered%0A            # list.%0A            if len(targets) != 0:%0A                changes = %7Btarget: replacement for target, replacement in%0A                           rule.changes.items() if target in targets%7D%0A                filtered_rules.append(Rule(changes, %5Benvironment%5D))%0A%0A    return filtered_rule
 s%0A%0Ai
@@ -2621,16 +2621,22 @@
 _':%0A    
+print(
 choose_r
@@ -2640,21 +2640,22 @@
 e_rule(words, rules)
+)
 %0A

Implement rule filtering and optimising by environment.