你的目标有很多挑战。我会把它们分成几部分。
SMILES 不是一个简单的解析语言,芳香感知的规则也没有很好的定义。OpenSMILES 项目中的详细语法定义应该会有所帮助。
SMILES 定义拓扑,但不提供 2D 或 3D 信息。做任何一个都很难。(也就是说,如果你想让它看起来不错。)
确实,您应该查看 RDKit 化学信息学工具包(或 OpenBabel,但我更喜欢 RDKit)。它有一个内置的 SMILES 解析器,以及 2D 布局,我相信 3D 构象生成。OpenBabel 也是如此。
然后为了显示,你必须弄清楚 GUI 系统。实际上,Java 中的 CDK 化学信息学工具包是最先进的。
但是您已经掌握了如何表示分子的基础知识。小分子和大分子(蛋白质、DNA)数据模型之间存在差异,但由于您对 SMILES 感兴趣,这意味着您是面向小分子的。
您可以查看 RDKit、OpenBabel、CDK、OEChem 和 Indigo 等的 API 文档。这将使您了解人们开发其类 API 的多种方式。其中,我最喜欢 OEChem,其次是 RDKit。尽管 OEChem 是开源的,但 API 是在线的并且可以免费阅读,并附有使用示例。
简而言之,有一个 Molecule 类,其中包含 Atom 和 Bond 实例的列表。"mol.AddAtom(element number)" 创建一个没有键的新原子,"mol.AddBond(atom1, atom2, bond_type)" 建立键连接。每个键都需要知道它所连接的原子,每个原子都需要一个键列表。这会导致数据结构中出现很多循环,但需要这样才能在线性时间内完成各种算法,例如连通性搜索。
不要使用二维矩阵。虽然对于小分子是可行的,但它的扩展性并不好,也没有必要。很少有算法需要连接矩阵,并且在需要时很容易生成。
没有“功能组”。太专业了 使用诸如“子集”或“片段”之类的东西,其中包含您感兴趣的原子和键的列表。这样,您还可以通过参考来处理诸如“选定原子”和“环子结构”和“脚手架”之类的东西特定的子集。
我看了你的pastebin。解析器不应该那样工作。您应该将解析与实际分子结构分开。尝试这样的事情:
class Molecule(object):
def __init__(self):
self.atoms = []
self.bonds = []
self._atom_id = 0
self._bond_id = 0
def _next_atom_id(self):
atom_id = self._atom_id
self.atom_id += 1
return atom_id
def AddAtom(self, eleno):
self.atoms.append(Atom(self, self._next_atom_id(), eleno))
def AddBond(self, atom1, atom2, bondtype):
assert atom1.molecule is atom2.molecule
self.bonds.append(Bond(self, self._next_bond_id(),
atom1, atom2, bondtype))
class Atom(object):
def __init__(self, molecule, id, eleno):
self.molecule = molecule
self.id = id
self.eleno = eleno
self.charge = 0
self.isotope = 0
..
然后像“CC O”这样的简单线性链的解析器是:
def parse_linear_chain(text):
mol = Molecule()
prev_atom = None
for atom_symbol in text.split():
eleno = lookup_symbol[atom_symbol]
atom = mol.NewAtom(eleno)
if pre_atom is not None:
mol.AddBond(prev_atom, atom, 1)
prev_atom = atom
return mol
当然,完整的 SMILES 解析器比这复杂得多,完整的数据模型必须处理诸如氢计数之类的事情,这些事情通常是隐含的。
如果您决定使用其中一个工具包,OpenBabel、RDKit 和 CDK 邮件列表也是不错的选择。还有由 Shapado 主持的“蓝色方尖碑”问答网站。