Как мне проанализировать химическую формулу с помощью регулярного выражения?

#python #regex #string

#python #регулярное выражение #строка

Вопрос:

У меня есть список шаблонов:

 patterns=['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al',
       'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn',
       'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb',
       'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In',
       'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm',
       'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta',
       'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At',
       'Rn']
 

и у меня есть большой фрейм данных со строками, например:

 str0='Mg0.97Fe0.03B2'
str1='Tl0.5Hg0.5Ba2Ca2Cu3O8'
 

Я пытаюсь это:

 keyss=list(filter(None,regex.split("[^a-zA-Z]*",somestring)))
values=list(filter(None,regex.split("[^0-9.0-9]*",somestring)))
 

Иногда это работает:

 str3='Hg0.75SrBa2Ca2Cu3O8'
keyss=list(filter(None,regex.split("[^a-zA-Z]*",str3)))
values=list(filter(None,regex.split("[^0-9.0-9]*",str3))
['Ba', 'Fe', 'Co', 'Mn', 'As']
['1', '1.832', '0.15', '0.018', '2']
 

Однако, если у меня есть строка, подобная этой:

 str3='Hg0.75SrBa2Ca2Cu3O8'
keyss=list(filter(None,regex.split("[^a-zA-Z]*",str3)))
values=list(filter(None,regex.split("[^0-9.0-9]*",str3)))
['Hg', 'SrBa', 'Ca', 'Cu', 'O']!=['Hg', 'Sr','Ba', 'Ca', 'Cu', 'O']
['0.75', '2', '2', '3', '8']!=['0.75', '1','2', '2', '3', '8']
 

или это

 str4='NbSn3'
keyss=list(filter(None,regex.split("[^a-zA-Z]*",str4)))
values=list(filter(None,regex.split("[^0-9.0-9]*",str4)))
['NbSn']!=['Nb','Sn']
['3']!=['1','3']
str4='Pb1.4Sr4Y1.2Ca0.8Cu4.6O'
...
 

Мой код работает некорректно. Как я могу это исправить?

Комментарии:

1. Проверка pypi.org/project/chemparse . Возможно, вам это пригодится

2. Какова здесь конечная цель? Учитывая строку химической формулы IUPAC, какой вывод вы хотите?

3. Каким должен быть результат для HS [1,1]?

4. Да, для HS должен быть вывод [1,1], спасибо за pypi.org/project/chemparse эта библиотека работает очень хорошо, она анализирует все строки, кроме одной) ‘BaKBi1O3’

5. Конечная цель — создать базу данных для обучения некоторых моделей ml

Ответ №1:

Я думаю, вы хорошо начали patterns , а затем отказались от идеи, которая, вероятно, бесполезна (вы могли бы использовать ее в pyparsing грамматике), но действительно есть более простой подход, который следует вашей последней идее.

Я предлагаю вам сделать что-то вроде этого:

 str3='Hg0.75SrBa2Ca2Cu3O8'
splitted = list(regex.split("([A-Z][a-z]*)",str3))
keyss = list(filter(lambda a: a[0].isupper() if a else False, splitted))
values = list(filter(lambda a: a[0].isdigit() if a else False, splitted))
print(keyss, values)
 

[‘Hg’, ‘Sr’, ‘Ba’, ‘Ca’, ‘Cu’, ‘O’] [‘0.75’, ‘2’, ‘2’, ‘3’, ‘8’]

Ответ №2:

Использовать

 import pandas as pd

patterns=['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al',
       'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn',
       'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb',
       'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In',
       'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm',
       'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta',
       'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At',
       'Rn']
rx = fr'({"|".join(sorted(patterns, key=len,reverse=True))})(d (?:.d )?)?'
df = pd.DataFrame({'formulas' : ['Mg0.97Fe0.03B2', 'Tl0.5Hg0.5Ba2Ca2Cu3O8', 'Hg0.75SrBa2Ca2Cu3O8', 'NbSn3']})
df['result'] = df['formulas'].str.findall(rx)
df['result'] = df['result'].apply(lambda m: [(x,y) if y else (x,1) for x,y in m])
 

Результаты

 >>> df
                formulas                                                     result
0         Mg0.97Fe0.03B2                           [(Mg, 0.97), (Fe, 0.03), (B, 2)]
1  Tl0.5Hg0.5Ba2Ca2Cu3O8  [(Tl, 0.5), (Hg, 0.5), (Ba, 2), (Ca, 2), (Cu, 3), (O, 8)]
2    Hg0.75SrBa2Ca2Cu3O8   [(Hg, 0.75), (Sr, 1), (Ba, 2), (Ca, 2), (Cu, 3), (O, 8)]
3                  NbSn3                                         [(Nb, 1), (Sn, 3)]
 

Комментарии:

1. Если что-то не так с решением, я был бы рад услышать.