una tipos quimico quimicas quimica partes molecular lenguaje estructural empirica electronica ejemplos ecuacion condensada como calcular basicas java chemistry

java - tipos - partes de una formula quimica



Analizar una fórmula química (5)

¿Ha buscado expresar sus fórmulas químicas en el lenguaje de marcado químico ? Es muy versátil y existen muchas herramientas / visores que pueden convertir estas fórmulas o compuestos químicos en 2D a 3D.

Estoy intentando escribir un método para una aplicación que toma una fórmula química como "CH3COOH" y devuelve algún tipo de colección llena de sus símbolos.

CH3COOH devolvería [C, H, H, H, C, O, O, H]

Ya tengo algo que funciona bastante bien, pero es muy complicado y usa mucho código con muchas estructuras y bucles anidados if-else.

¿Hay alguna manera de hacer esto usando algún tipo de expresión regular con String.split o tal vez en algún otro código simple y brillante?


Estoy trabajando en un programa que requiere cálculos de masa molar de fórmulas químicas, así que he creado una solución que funciona con una variedad de fórmulas.

Por ejemplo, "(CH3) 16 (Tc (H2O) 3CO (BrFe3 (ReCl) 3 (SO4) 2) 2) 2MnO4" resultará en "16C 48H 2Tc 12H 6O 2C 2O 4Br 12Fe 12Re 12Cl 8S 32O Mn 4O" ( este compuesto está hecho, pero bueno, ¡funciona!)

Este código está escrito en C #, por eso no lo he publicado. Si te interesa puedo publicarlo por ti. De hecho, escribí una respuesta completa antes de darme cuenta de la etiqueta java.

De todos modos, funciona básicamente agrupando recursivamente bloques de átomos emparejados por paréntesis. No maneja coeficientes como 2Pb (pero (Pb) 2 o Pb2 funciona) o compuestos cargados como OH-.

De ninguna manera es simple o elegante. Quería una solución funcional, así que sé que hay mejores maneras (¡ni siquiera probé las expresiones regulares!). Pero funciona con las fórmulas que necesito, quizás también se adapte a las tuyas.

Aquí hay algunos casos de prueba en los que lo ejecuto. Míralos y hazme saber si el código C # aún sería útil para ti. El formato es (entrada, salida esperada).

("Pb ", " Pb"); ("H ", " H"); ("Pb2 ", " 2Pb"); ("H2 ", " 2H"); ("3Pb2 ", " 6Pb"); ("Pb2SO4", " 2Pb S 4O"); ("PbH2 ", " Pb 2H"); ("(PbH2)2 ", " 2Pb 4H"); ("(CCC)2 ", " 2C 2C 2C"); ("Pb(H2)2 ", " Pb 4H"); ("(Pb(H2)2)2 ", " 2Pb 8H"); ("(Pb(H2)2)2NO3 ", " 2Pb 8H N 3O"); ("(Ag(Pb(H2)2)2)2SO4 ", " 2Ag 4Pb 16H S 4O"); ("Pb(CH3(CH2)2CH3)2", " Pb 2C 6H 4C 8H 2C 6H"); ("Na2(CH3(CH2)2CH3)2", " 2Na 2C 6H 4C 8H 2C 6H"); ("Tc(H2O)3Fe3(SO4)2", " Tc 6H 3O 3Fe 2S 8O"); ("Tc(H2O)3(Fe3(SO4)2)2", " Tc 6H 3O 6Fe 4S 16O"); ("(Tc(H2O)3(Fe3(SO4)2)2)2", " 2Tc 12H 6O 12Fe 8S 32O"); ("(Tc(H2O)3CO(Fe3(SO4)2)2)2", " 2Tc 12H 6O 2C 2O 12Fe 8S 32O"); ("(Tc(H2O)3CO(BrFe3(ReCl)3(SO4)2)2)2MnO4", " 2Tc 12H 6O 2C 2O 4Br 12Fe 12Re 12Cl 8S 32O Mn 4O"); ("(CH3)16(Tc(H2O)3CO(BrFe3(ReCl)3(SO4)2)2)2MnO4", " 16C 48H 2Tc 12H 6O 2C 2O 4Br 12Fe 12Re 12Cl 8S 32O Mn 4O");


He desarrollado un par de series de artículos sobre cómo analizar fórmulas moleculares, incluidas fórmulas más complejas como C6H2 (NO2) 3CH3.

La más reciente es mi presentación " PLY y PyParsing " en PyCon2010, donde comparo esos dos sistemas de análisis de Python utilizando un evaluador de fórmula molecular como mi problema de muestra. Incluso hay un video de mi presentación .

La presentación se basó en una serie de artículos de tres partes que hice desarrollando un analizador de fórmula molecular con ANTLR. En la parte 3 comparo la solución ANTLR con un analizador de expresiones regulares escrito a mano y soluciones en PLY y PyParsing.

Las soluciones regexp y PLY se desarrollaron por primera vez en una serie de dos partes sobre dos formas de escribir analizadores en Python.

La solución de expresión regular y las soluciones de base ANTLR / PLY / PyParsing, usan una expresión regular como [AZ] [az]? / D * para hacer coincidir los términos en la fórmula. Esto es lo que sugirió @David M

Aquí está resuelto en Python.

import re # element_name is: capital letter followed by optional lower-case # count is: empty string (so the count is 1), or a set of digits element_pat = re.compile("([A-Z][a-z]?)(/d*)") all_elements = [] for (element_name, count) in element_pat.findall("CH3COOH"): if count == "": count = 1 else: count = int(count) all_elements.extend([element_name] * count) print all_elements

Cuando ejecuto esto (es difícil usar ácido acético, CH3COOH), obtengo

[''C'', ''H'', ''H'', ''H'', ''C'', ''O'', ''O'', ''H'']

Tenga en cuenta que este pequeño fragmento de código supone que la fórmula molecular es correcta. Si le da algo como "## $% ^ O2 # $$ #", ignorará los campos que no conoce y le dará [''O'', ''O'']. Si no quieres eso, tendrás que hacerlo un poco más robusto.

Si desea admitir fórmulas más complicadas, como C6H2 (NO2) 3CH3, entonces necesitará saber un poco acerca de las estructuras de datos de los árboles, específicamente (como señala @Roman), los árboles de sintaxis abstracta (la mayoría de las veces se llama AST). Eso es demasiado complicado para entrar aquí, así que vea mis charlas y ensayos para obtener más detalles.


La solución con expresiones regulares es el mejor enfoque si necesita manejar solo casos simples. De lo contrario, debe crear algo como el árbol de sintaxis abstracta y evaluar o usar la notación polaca .

Por ejemplo, la fórmula de TNT C6H2(NO2)3CH3 debe presentarse como:

(+ (* C 6) (* H 2) (* (+ N (* O 2)) 3) C (+ H 3))


Suponiendo que esté correctamente en mayúsculas, cada símbolo en la ecuación coincide con esta expresión regular:

[A-Z][a-z]*/d*

(Para los que tienen un problema químico, el símbolo de un elemento siempre es mayúscula seguido de una opción en mayúscula o posiblemente dos, por ejemplo, Hg para mercurio)

Puede capturar el símbolo del elemento y el número en grupos así:

([A-Z][a-z]*)(/d*)

Entonces sí, en teoría, esto sería algo en lo que las expresiones regulares podrían ayudar. Si está tratando con fórmulas como C 6 H 2 (NO 2 ) 3 (CH 3 ) 3, entonces su trabajo es, por supuesto, un poco más difícil ...