I was trying to find a way to separate strings in a project of my called 'Chemistry Calculator'. This project takes strings from an input() and compare it in a list:
substance1 = input('Substance 1: ')
substance2 = input('Substance 2: ')
elements = ['f','o','cl','br','i','s','c']
def affinity_table(element1:str,element2:str,table:list) -> str:
s = element1.lower()
r = element2.lower()
if s in table and r in table:
if table.index(s) < table.index(r):
print(s," will chage with ", r)
else:
print(s," won't change with ", r)
else:
print("Those substances are't in the list")
This code above works well.
So I wanted to have it working with hole substances and not just the element. To do this I need to separate the substance in to parts:
Then I need to compare them with the list. I noticed that the contains() function showed exactly what I wanted, but only with one comparison.
My question came from: Is there a way of using the contains() function with more than one string and then separate the string in to where the similarity is found.
Something similar to this:
a = 'NaCO3' #First input.
b = 'KCO3' #Second input.
list = ['Na','K'] #The list.
# Way of separating the values with the list.
# ^ my objective.
a1 = 'Na' #Separation with a.
a2 = 'CO3' #The rest of a.
b1 = 'K' #The rest of b.
b2 = 'CO3' #The rest of b.
# ^ expected outputs from the separation.
if table.index(a1) < table.index(a2):
print(a1,' will change with ', b1, 'and become', a1 + b2)
else:
print(a1," won't change with ", b1, 'and will stay normal')
# ^ the list index comparison from the 1st code.
#After the solution, here are the results:

Disclaimer
Just to be clear: for the constrained scope of what you are doing this solution might be applicable. If you want to parse any chemical compound (and those can look quite complicated) you need a full fledged parser, not the toy regex solution I came up with.
Here's an idea:
Dynamically build a regex with elements from your list as alternating matching groups. (re.split keeps groups when splitting.)
>>> import re
>>> lst = ['Na', 'K']
>>> regex = '|'.join('({})'.format(a) for a in lst)
>>> regex
>>> '(Na)|(K)'
Apply the regex...
>>> re.split(regex, 'NaCO3')
>>> ['', 'Na', None, 'CO3']
>>> re.split(regex, 'KCO3')
>>> ['', None, 'K', 'CO3']
... and filter out falsy values (None, '')
>>> list(filter(None, re.split(regex, 'NaCO3')))
>>> ['Na', 'CO3']
>>> list(filter(None, re.split(regex, 'KCO3')))
>>> ['K', 'CO3']
You can assign to those values with extended iterable unpacking:
>>> b1, b2, *unexpected_rest = filter(None, re.split(regex, 'KCO3'))
>>> b1
>>> 'K'
>>> b2
>>> 'CO3'
If you want to bias the split in favor of longer matches, sort lst in descending order first.
Not good:
>>> lst = ['N', 'Na', 'CO3']
>>> regex = '|'.join('({})'.format(a) for a in lst)
>>> list(filter(None, re.split(regex, 'NaCO3')))
>>> ['N', 'a', 'CO3']
Better:
>>> lst = ['N', 'Na', 'CO3']
>>> lst = sorted(lst, key=len, reverse=True)
>>> regex = '|'.join('({})'.format(a) for a in lst)
>>> list(filter(None, re.split(regex, 'NaCO3')))
>>> ['Na', 'CO3']
Let me know if that works for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With