Enable multiple changes and strings
This commit is contained in:
parent
b7a700b375
commit
a8928cf715
@ -1,18 +1,45 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
def apply(change, string, categories={}, apply=True, zero_characters=['∅']):
|
def apply(changes, strings, categories={}, apply=True, zero_characters=['∅']):
|
||||||
"""Apply a sound change to a given string"""
|
"""Apply a sound change to a given string"""
|
||||||
|
|
||||||
if not apply:
|
if not apply:
|
||||||
return string
|
return strings
|
||||||
|
|
||||||
# Check validity of change
|
if isinstance(changes, str):
|
||||||
|
changes = [changes]
|
||||||
|
|
||||||
|
return_str = isinstance(strings, str)
|
||||||
|
if isinstance(strings, str):
|
||||||
|
strings = [strings]
|
||||||
|
|
||||||
|
for change in changes:
|
||||||
|
validate_change(change)
|
||||||
|
change = convert_change_to_regex(change, categories=categories, zero_characters=zero_characters)
|
||||||
|
|
||||||
|
original, change_to, before, after = split_change(change)
|
||||||
|
|
||||||
|
pattern = f"({before})({original})({after})"
|
||||||
|
last_group_index = pattern.count('(') - after.count('(')
|
||||||
|
replacement = f"\\1{change_to}\\{last_group_index}"
|
||||||
|
|
||||||
|
for i, string in enumerate(strings):
|
||||||
|
strings[i] = re.sub(pattern, replacement, f"#{string}#").strip('#')
|
||||||
|
|
||||||
|
if return_str:
|
||||||
|
return strings[0]
|
||||||
|
return strings
|
||||||
|
|
||||||
|
|
||||||
|
def validate_change(change):
|
||||||
if change.count('>') != 1:
|
if change.count('>') != 1:
|
||||||
raise ValueError(f"Change {change} is not a valid sound change. (Missing character '>')")
|
raise ValueError(f"Change {change} is not a valid sound change. (Missing character '>')")
|
||||||
if change.count('/') > 1:
|
if change.count('/') > 1:
|
||||||
raise ValueError(f"Change {change} is not a valid sound change. (More than one '/' character)")
|
raise ValueError(f"Change {change} is not a valid sound change. (More than one '/' character)")
|
||||||
|
|
||||||
|
|
||||||
|
def convert_change_to_regex(change, categories, zero_characters):
|
||||||
# Prepare change for regex
|
# Prepare change for regex
|
||||||
for k, v in {' ': '', '{': '(', '}': ')', ',': '|'}.items():
|
for k, v in {' ': '', '{': '(', '}': ')', ',': '|'}.items():
|
||||||
change = change.replace(k, v)
|
change = change.replace(k, v)
|
||||||
@ -24,6 +51,14 @@ def apply(change, string, categories={}, apply=True, zero_characters=['∅']):
|
|||||||
# Replacements of categories anywhere else
|
# Replacements of categories anywhere else
|
||||||
change = change.replace(k, '('+'|'.join(v)+')')
|
change = change.replace(k, '('+'|'.join(v)+')')
|
||||||
|
|
||||||
|
# Remove zero characters
|
||||||
|
for char in zero_characters:
|
||||||
|
change = change.replace(char, '')
|
||||||
|
|
||||||
|
return change
|
||||||
|
|
||||||
|
|
||||||
|
def split_change(change):
|
||||||
if '/' in change:
|
if '/' in change:
|
||||||
change, environment = change.split('/')
|
change, environment = change.split('/')
|
||||||
else:
|
else:
|
||||||
@ -41,12 +76,4 @@ def apply(change, string, categories={}, apply=True, zero_characters=['∅']):
|
|||||||
if not original:
|
if not original:
|
||||||
raise ValueError(f"Nothing to change from.")
|
raise ValueError(f"Nothing to change from.")
|
||||||
|
|
||||||
# Remove zero characters
|
return (original, change_to, before, after)
|
||||||
for char in zero_characters:
|
|
||||||
change_to = change_to.replace(char, '')
|
|
||||||
|
|
||||||
pattern = f"({before})({original})({after})"
|
|
||||||
last_group_index = pattern.count('(') - after.count('(')
|
|
||||||
replacement = f"\\1{change_to}\\{last_group_index}"
|
|
||||||
|
|
||||||
return re.sub(pattern, replacement, f"#{string}#").strip('#')
|
|
||||||
@ -41,9 +41,7 @@ def test_complex_environment():
|
|||||||
inputs = ['pana', 'pina', 'puna', 'pama', 'pima', 'puma']
|
inputs = ['pana', 'pina', 'puna', 'pama', 'pima', 'puma']
|
||||||
outputs = ['pana', 'hina', 'huna', 'pama', 'hima', 'huma']
|
outputs = ['pana', 'hina', 'huna', 'pama', 'hima', 'huma']
|
||||||
for string, output in zip(inputs, outputs):
|
for string, output in zip(inputs, outputs):
|
||||||
assert apply(
|
assert apply('p>h/#_{u,i}Na#', string,
|
||||||
change='p>h/#_{u,i}Na#',
|
|
||||||
string=string,
|
|
||||||
categories={'N': 'nm'}
|
categories={'N': 'nm'}
|
||||||
) == output
|
) == output
|
||||||
|
|
||||||
@ -54,7 +52,7 @@ def test_complex_group_and_categories():
|
|||||||
'N': 'mn',
|
'N': 'mn',
|
||||||
}) == 'pani'
|
}) == 'pani'
|
||||||
|
|
||||||
def test_with_complex_group_and_categories_and_digraphs():
|
def test_complex_group_and_categories_and_digraphs():
|
||||||
assert apply('u>o/#V{ts,pf,t}_k{V,e,o}#', 'atsuka', categories={
|
assert apply('u>o/#V{ts,pf,t}_k{V,e,o}#', 'atsuka', categories={
|
||||||
'V': ['a', 'i', 'u']
|
'V': ['a', 'i', 'u']
|
||||||
}) == 'atsoka'
|
}) == 'atsoka'
|
||||||
@ -65,13 +63,28 @@ def test_with_complex_group_and_categories_and_digraphs():
|
|||||||
'V': ['a', 'i', 'u']
|
'V': ['a', 'i', 'u']
|
||||||
}) == 'matsuka'
|
}) == 'matsuka'
|
||||||
|
|
||||||
|
def test_change_from_category():
|
||||||
|
assert apply('V>o', 'tatiru', categories={
|
||||||
|
'V': 'aiu'
|
||||||
|
}) == 'totoro'
|
||||||
|
|
||||||
|
def test_list_and_str_inputs():
|
||||||
|
assert apply('a>b', 'cad') == 'cbd'
|
||||||
|
assert apply(['a>b'], 'cad') == 'cbd'
|
||||||
|
assert apply('a>b', ['cad']) == ['cbd']
|
||||||
|
assert apply(['a>b'], ['cad']) == ['cbd']
|
||||||
|
|
||||||
def test_multiple_changes():
|
def test_multiple_changes():
|
||||||
string = 'pana'
|
string = 'pana'
|
||||||
for change in ['p>f', 'n>m/fa_']:
|
for change in ['p>f', 'n>m/fa_']:
|
||||||
string = apply(change, string)
|
string = apply(change, string)
|
||||||
assert string == 'fama'
|
assert string == 'fama'
|
||||||
|
assert apply(['p>f', 'n>m/fa_'], string) == 'fama'
|
||||||
|
|
||||||
def test_change_from_category():
|
def test_multiple_strings():
|
||||||
assert apply('V>o', 'tatiru', categories={
|
assert apply('p>f', ['pana', 'pune']) == [
|
||||||
'V': 'aiu'
|
'fana', 'fune'
|
||||||
}) == 'totoro'
|
]
|
||||||
|
|
||||||
|
def test_multiple_changes_and_strings():
|
||||||
|
assert apply(['p>f', 'f>h/#_a'], ['pana', 'pune']) == ['hana', 'fune']
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user