SMILES(Simplified Molecular Input Line Entry System)把分子的二维结构编码成一行字符串。它是化学信息学中最基础的表示——理解它的规则与局限,是做任何分子数据工作的前提。
基本语法
# 【原子】
# C, N, O, S, P, F, Cl, Br, I 有机子集,可省略方括号
# [Na+], [Fe+2], [nH], [13C] 需要方括号(电荷、同位素、显式氢)
# 小写 = 芳香原子:c, n, o, s
#
# CC 乙烷(氢是隐含的)
# C=C 乙烯
# C#C 乙炔
#
# 【键】
# - 单键(通常省略)
# = 双键
# # 三键
# : 芳香键(通常省略,用小写原子表示)
#
# 【分支:用括号】
# CC(C)C 异丁烷
# CC(=O)O 乙酸
# CC(=O)Nc1ccc(O)cc1 对乙酰氨基酚
#
# 【环:用数字标记闭合】
# C1CCCCC1 环己烷
# c1ccccc1 苯(芳香写法)
# C1=CC=CC=C1 苯(凯库勒写法)
# c1ccc2ccccc2c1 萘(两个环,用不同数字)
#
# 【立体化学】
# 顺反异构:/ 和 \
# F/C=C/F 反式
# F/C=C\F 顺式
# 手性:@ 和 @@
# N[C@@H](C)C(=O)O L-丙氨酸
# N[C@H](C)C(=O)O D-丙氨酸
#
# 【断开的组分:用点】
# CC(=O)[O-].[Na+] 乙酸钠
# → 【盐、溶剂化物用这种方式表示】
#
# 【常见的记忆点】:
# 环闭合数字可以复用(一个环闭合后数字释放)
# 芳香性由 RDKit 感知,不同写法可以等价
规范化:最重要的概念
# 【同一个分子有无数种 SMILES 写法】
# 苯:c1ccccc1、C1=CC=CC=C1、c1ccc(cc1)、...
#
# 【后果】:
# 直接比较字符串会把同一分子当成不同的
# → 去重、匹配、连接数据都会出错
#
# 【解决:规范 SMILES(canonical SMILES)】
# 用确定的算法选择唯一的写法
from rdkit import Chem
def canonical(smiles):
mol = Chem.MolFromSmiles(smiles)
return Chem.MolToSmiles(mol) if mol else None
print(canonical("c1ccccc1")) # c1ccccc1
print(canonical("C1=CC=CC=C1")) # c1ccccc1
# 【相同】
# 【重要提醒】:
# 1) 【规范算法是工具特定的】
# RDKit 的规范 SMILES 与 OpenBabel 的可能不同
# → 【跨工具比较必须用同一个工具规范化】
#
# 2) 规范化【不】处理:
# - 盐型(CC(=O)[O-].[Na+] vs CC(=O)O)
# - 互变异构体
# - 不同的质子化态
# → 【这些需要专门的标准化流程】(见 046)
#
# 3) 立体化学的处理
# Chem.MolToSmiles(mol, isomericSmiles=False)
# 会去掉立体信息 —— 【有时需要,但要明确】
# 【实践建议】:
# 数据入库时统一规范化并存储规范 SMILES
# → 之后所有的匹配、去重都基于它
SMILES 的信息含量与局限
| 包含 | 不包含 |
|---|---|
| 原子类型与连接 | 三维坐标 |
| 键级 | 构象 |
| 形式电荷 | 实际的电荷分布 |
| 立体化学(如果标注) | 互变异构体的实际比例 |
| 同位素 | 晶型/固态形式 |
| 芳香性感知 | 溶液中的实际状态 |
最需要注意的两个局限:SMILES 不含三维信息(做对接或三维建模时必须另外生成构象,见 049《构象生成入门》);SMILES 表示的是「一个」互变异构体或质子化态,而分子在溶液中可能是多种形式的平衡。
SMARTS:用于子结构匹配的扩展
# SMILES 描述【具体的分子】
# SMARTS 描述【一类结构模式】
from rdkit import Chem
# 基本用法
patt = Chem.MolFromSmarts("c1ccccc1") # 苯环
mol = Chem.MolFromSmiles("CC(=O)Nc1ccc(O)cc1")
print(mol.HasSubstructMatch(patt)) # True
print(mol.GetSubstructMatches(patt)) # 匹配的原子索引
# SMARTS 特有的语法:
# * 任意原子
# [C,N] 碳或氮
# [!C] 非碳
# [#6] 原子序数 6(碳),包括芳香与脂肪
# [CX4] 四价碳(sp3)
# [OH] 带一个氢的氧(羟基)
# [NX3;H2,H1;!$(NC=O)] 非酰胺的伯胺或仲胺
# ~ 任意键
# @ 环键
# [r5] 五元环中的原子
# $(...) 递归 SMARTS
#
# 【常用的官能团模式】:
PATTERNS = {
"羧酸": "[CX3](=O)[OX2H1]",
"伯胺": "[NX3;H2;!$(NC=O)]",
"酰胺": "[NX3][CX3](=[OX1])",
"酯": "[CX3](=O)[OX2H0][#6]",
"硝基": "[NX3+](=O)[O-]",
"卤代烷": "[CX4][F,Cl,Br,I]",
"芳香羟基": "[OX2H][c]",
"迈克尔受体": "[CX3]=[CX3][CX3]=[OX1]", # 共价弹头(见 379)
}
def count_groups(smiles):
mol = Chem.MolFromSmiles(smiles)
if mol is None:
return None
return {name: len(mol.GetSubstructMatches(Chem.MolFromSmarts(p)))
for name, p in PATTERNS.items()}
# 【SMARTS 是结构警示过滤的基础】(见 069)
# 【写 SMARTS 的建议】:
# 1) 写完后一定要在正例与反例上测试
# 2) 注意芳香性:c 与 C 不等价
# 3) 用 [#6] 而非 C 可以同时匹配芳香与脂肪碳
常见陷阱
- 解析失败静默返回 None:必须检查,否则后续操作会抛出难以理解的错误;
- 芳香性的感知差异:不同工具对某些环系(如某些杂环)的芳香性判断可能不同——跨工具传递数据时要注意;
- 立体化学未指定:SMILES 中不写 @ 表示「未指定」而非「没有手性」——生成三维构象时会随机分配;
- 盐与混合物:用
.分隔的多组分,建模时通常要去掉抗衡离子(见 047《去盐与去重复》); - 过长的 SMILES:大分子(如多肽、大环)的 SMILES 可能很长,某些工具有长度限制;
- 特殊字符的转义:SMILES 中的
\在字符串处理中要注意转义(Python 中用原始字符串)。
关键要点
- 同一分子有无数种写法——必须用规范 SMILES 才能正确比较与去重;
- 规范算法是工具特定的——跨工具比较必须用同一个工具规范化;
- 规范化不处理盐型、互变异构体与质子化态,这需要专门的标准化流程;
- SMILES 不含三维信息;未指定立体化学 ≠ 没有手性。
延伸资源
- SELFIES:032《SELFIES 入门》;InChI:033《InChI 与 InChIKey》;分子图:034《分子图表示》;
- 分子标准化:046《分子标准化》;构象生成:049《构象生成入门》;RDKit:013《RDKit Cookbook》。