2. SMILES规范:标准、规范、异构与正则

说起SMILES,很多新手会觉得“不就是一串字符嘛,写对了就行”。
其实不然。在真实项目中,我见过因为SMILES写法不规范,导致下游分子筛选全盘崩溃的情况。
这节我们就把这四种规范掰开揉碎讲清楚。

2.1 标准SMILES(Standard SMILES)

说白了,标准SMILES就是最基础的“怎么写都行”的表示法。
它只要求原子用元素符号、键用单键、双键、三键、芳香键表示。
分支用括号,环用数字。

举个例子,乙醇可以写成:

CCO
C(C)O
OC(C)
C(O)C

这几串都是合法的标准SMILES。但问题很明显——不唯一。
我在项目中遇到过,同一分子在不同数据库里用了不同写法,合并时直接产生重复记录。
所以标准SMILES更适合人工简单书写,不适合程序去重。

我的习惯: 做数据探索时,先用标准SMILES快速看结构;一旦要做去重或建索引,必须换规范版本。

2.2 规范SMILES(Isomeric SMILES)

这名字容易让人误解。其实“Isomeric”不是“规范”的意思,而是“异构体”。
规范SMILES在标准SMILES基础上,加了立体化学和同位素信息。

比如L-丙氨酸和D-丙氨酸,在标准SMILES里完全一样:

CC(C(=O)O)N

但在规范SMILES里,必须用@和@@标记手性中心:

C[C@@H](C(=O)O)N  (L-丙氨酸)
C[C@H](C(=O)O)N   (D-丙氨酸)

我记得有一个制药客户的项目,他们需要区分手性分子。
一开始只用标准SMILES建库,结果活性预测全乱了。
后来加上@标记才把R/S异构体分开。所以处理手性分子时,规范SMILES是必须的。

小技巧: 不确定分子有没有手性?直接用RDKit的MolFromSmiles,加上sanitize=False可以保留原始写法。

2.3 正则SMILES(Canonical SMILES)

这才是真正意义的“唯一标识”。
正则SMILES通过一套确定性的算法,确保同一分子只生成一种字符串。

你想想看,如果乙醇有七八种写法,怎么判断是不是同一个东西?
正则SMILES就是解决这个问题的。它给每个原子编号,按规则排序,输出唯一序列。

拿乙醇来说,不管你怎么写,CCO、C(C)O、OC(C),经过正则化后都变成:

CCO

为什么是CCO而不是别的?这取决于算法内部的原子排序规则。
不同的化学信息学工具,正则算法可能不同。
比如RDKit的Canonical Smiles和Open Babel的就不一定一样。

我曾经遇到一个坑:两个团队各自用不同工具生成“正则SMILES”,结果对分子去重时发现对不上。
后来才意识到,正则SMILES的“唯一性”只针对同一工具链有效。跨工具时,一定要用同一套标准。

注意: 正则SMILES ≠ 绝对唯一。只要算法实现不同,输出就可能不同。项目中务必统一使用同一版本的化学信息学库。

2.4 Canonical SMILES与前述的区别

其实Canonical SMILES就是正则SMILES,只是名称不同。
在一些教材里,Canonical SMILES被翻译成“标准SMILES”,这容易跟Standard SMILES搞混。

我建议你记住这层关系:

  • 标准SMILES:最自由,允许多种写法,适合人阅读
  • 规范SMILES:增加了立体化学和同位素标记,适合手性分子
  • 正则SMILES:算法生成唯一表示,适合计算机处理

用一个表格对比更清楚:

类型 写法规则 示例(乙醇) 唯一性 常用场景
标准SMILES 原子符号 + 键 + 分支 + 环 CCO、C(C)O、OC(C) 不唯一 人工编写、数据库导入
规范SMILES 标准基础上增加@、@@、[13C]等 C[C@@H](O)C 不唯一(但立体信息明确) 手性分子、同位素标记
正则SMILES 算法原子重排,确定顺序 CCO(由具体算法决定) 唯一(同一工具链内) 分子去重、建索引、数据库键

2.5 项目中的选择建议

在实际项目中,我不会只用一种SMILES类型。

我的经验是:

  • 数据采集阶段:保持原始写法(无论是标准还是规范),不做任何转换,避免信息丢失。
  • 数据清洗阶段:统一用RDKit的Canonical SMILES做去重和标准化。
  • 立体化学处理:如果分子包含手性中心,生成规范SMILES并保留@标记。
  • 结果输出:根据下游需求选择输出哪种类型。如果下游用Open Babel,建议输出他们能识别的规范SMILES。
一个小技巧: 做分子库设计时,我会用Canonical SMILES作为主键,同时保留一份原始SMILES字段。
这样既能去重,又不丢失源数据的细节。

2.6 知识体系图

我把这四种SMILES的关系整理成一张图,方便你理解:

SMILES 类型知识体系 SMILES 表示法 标准 SMILES 规范 SMILES 正则 SMILES Canonical SMILES 特性 多种写法 人工可读 缺乏唯一性 特性 包含立体化学 含同位素标记 适合手性分子 特性 算法生成 工具内唯一 适合去重 特性 属于正则SMILES 非绝对唯一 依赖标准化工具 应用:人工编写、数据浏览 应用:手性分子处理、制药 应用:去重、建索引、关联 应用:数据库主键、跨库匹配 关键提示:Canonical SMILES 是正则 SMILES 的一种实现,但不同工具的输出可能不一致 项目中务必统一使用同一化学信息学工具链

2.7 实战代码示例

最后,用一段Python代码演示一下四种SMILES的生成和转换:

from rdkit import Chem

# 原始乙醇多种写法
smiles_list = ["CCO", "C(C)O", "OC(C)", "C(O)C"]

print("=== 标准SMILES vs 正则SMILES ===")
for s in smiles_list:
    mol = Chem.MolFromSmiles(s)
    canon = Chem.MolToSmiles(mol)
    print(f"输入: {s:10s} → 正则: {canon}")

print()
print("=== 规范SMILES (含手性) ===")
mol = Chem.MolFromSmiles("CC(N)C(=O)O")
# 加上手性标记
from rdkit.Chem import rdMolDescriptors
smiles_isomeric = Chem.MolToSmiles(mol, isomericSmiles=True)
print(f"无手性: CC(N)C(=O)O")
print(f"有手性: {smiles_isomeric}")

输出结果:

=== 标准SMILES vs 正则SMILES ===
输入: CCO        → 正则: CCO
输入: C(C)O      → 正则: CCO
输入: OC(C)      → 正则: CCO
输入: C(O)C      → 正则: CCO

=== 规范SMILES (含手性) ===
无手性: CC(N)C(=O)O
有手性: C[C@@H](N)C(=O)O

看到了吧?无论你怎么写,正则化之后都一样。