1. SMILES 基础:表示规则,原子,键,分支,环
讲 SMILES 之前,我想先聊聊我刚开始做化学信息学那会儿的事。那时候导师丢给我一个包含几万个小分子的文件,说“你把它们都转成线性表示,方便存到数据库里”。我当时满脑子问号——线性表示?怎么把立体结构拉成一条字符串?后来才知道,这东西叫 SMILES。说白了,它就是给分子画的一串“简易密码”,人能读,机器也能判。
这一节我们先把地基打牢。你要能看懂一个 SMILES 字符串里每个字符在说什么,也得能写出来。我个人认为,理解了这四块——原子、键、分支、环——你就掌握了 90% 的日常用法。
核心要点:SMILES 是一种基于图的线性编码,用原子符号、键符号、括号和数字来表示分子拓扑结构。支持手性、同位素和立体化学,但不保证唯一性(除非使用规范 SMILES)。
1.1 原子表示:从简单到复杂
最朴素的情况——元素符号直接写。比如 C 表示甲烷、O 表示水。你是不是觉得太简单了?嗯,但有个坑:周期表里那些两字母元素,比如 Cl、Br、Na,首字母大写、第二个字母小写,这是硬规矩。我第一次写 CL(两个大写)被解析器报了错,才老老实实记住。
那什么时候要给原子加方括号?当它需要携带额外信息时:
- 同位素:比如
[13C]表示碳‑13,[18O]表示氧‑18。 - 电荷:
[NH4+]铵根,[Fe+3]铁离子。正负电荷数用数字写在符号后,比如[O-]、[Mg+2]。 - 手性标记:
[C@@H]表示四面体中心为反式手性。我早期有个项目因为没加这个标记,生成了错误的异构体,后来补了 @ 符号才跑通。 - 氢原子数:
[CH3]表示一个碳连了三个氢,其实可以简写为C,但显式写出氢数在有些计算场景下更安全。
我的习惯:在写 SMILES 时,如果原子不是常见有机元素(C、N、O、S、P、卤素)或者它有电荷/同位素,就老老实实加方括号。除非你能确保下游解析器支持隐式写法,否则别图省事。
| 写法 | 含义 | 注意 |
|---|---|---|
C |
甲烷 (CH₄),或烷烃碳 | 氢原子自动补全至四价 |
[O] |
氧自由基 (不带电荷) | 与 O 等价,但显式提醒自由基存在 |
[NH3+] |
质子化氨 (铵根离子) | 电荷 +1,氢数显式说明 |
[13CH3] |
同位素标记的甲基 | 质量数 13,氢数目显式 |
1.2 键表示:单双三和芳香
键的表示很直接:
- 单键:不写任何符号,直接连原子。比如
CC就是乙烷。 - 双键:等号
=,比如C=C乙烯。 - 三键:井号
#,比如C#C乙炔。 - 芳香键:小写字母表示芳香环中的原子。比如
c1ccccc1表示苯环(所有碳用小写c,键默认是芳香键)。
我在做虚拟筛选时,遇到过一个坑:解析器把 c1ccccc1 里的六个碳当成了四个氢?不是的,解析器会自动推断苯环的芳香性,但不同库对“芳香”的定义有微妙差别。比如 RDKit 默认把吡啶的氮写为 n,而 Open Babel 可能要求显式双键。所以,如果你要跨工具流通,最好用规范 SMILES,也就是经过标准化后输出的字符串。举个例子:
# RDKit 生成的规范 SMILES
甲醇: CO
苯: c1ccccc1
吡啶: c1ccncc1
硝基苯: c1ccc(cc1)[N+](=O)[O-]
我曾经踩的雷:在一个批次里用 RDKit 生成了一批 SMILES,顺手保存了原始字符串。另一批用 Open Babel 处理,结果发现同样的分子(比如苯甲酸)在不同工具下 aromatic 标记不一样——RDKit 输出 c1ccccc1C(=O)O,Open Babel 输出 c1ccccc1C(=O)O 看起来一样,但内部原子顺序不同。后来我强制所有数据通过 RDKit 的 Chem.MolToSmiles 重写一遍,才统一了表示。你要是做跨批次一致性分析,记住:必须在同一解析器下做标准化,否则对不上。
1.3 分支结构:括号来凑
分支是 SMILES 里最常用的套路——用圆括号括住一个子结构,把它“挂”在某个原子上。举个例子,异丙醇(2-丙醇):
CC(C)O
解读一下:从左到右,第一个 C,然后第二个 C,遇到左括号 ( 表示一个分支从当前原子(第二个碳)开始,括号里是 C,之后闭合括号,继续主链走 O。所以这个分子是:中间的碳连了一个甲基(分支)和一个羟基。
分支可以嵌套,也可以有多个并列:
# 2-氨基-1-丙醇
NC(C)CO
# 叔丁醇
CC(C)(C)O
# 更复杂的:L-苏氨酸(简化)
C[C@@H]([C@H](C(=O)O)N)O
我个人习惯是先画主链,再往主链上挂分支。如果你要手动写 SMILES,不妨用“可视化-还原法”:把分子画出来,找到最长连续碳链作为主线,其余作为分支依次插入。
1.4 环结构:数字标记
环是 SMILES 里最容易写错的地方。规则很简单:用数字(0-9)来标记同一个环的起点和终点。比如环己烷:
C1CCCCC1
数字 1 先出现在第一个碳后,表示这个环的起点是第一个碳;当第二次出现 1 时(最后一个碳),表示这个环在这里闭合。注意,数字对同一个环必须配对,且不能重复——你不能在同一分子里用两个 1 号表示不同的环。RDKit 会自动分配数字,但手写时记得检查配对。
芳香环常用小写 + 数字:
# 苯
c1ccccc1
# 萘(两个稠环)
c1ccc2ccccc2c1
这里 c1 起,遇到 2 开始第二个环标记,最后 c1 闭合第一个环。你会发现数字可以像变量一样,在字符串里多次出现,但要保证成对且不冲突。我遇到过一个项目,别人写的 SMILES 里数字用了 1 和 01(零一),解析器把 01 当作数字 1 处理,结果环出错。所以别用 0 作为环标记的开头——01 会被理解为 1。
避坑指南:手写环状 SMILES 时,我建议先用纸笔画一遍结构,确认环的断开点(也就是数字出现的位置)。然后用小工具(比如 ChemDraw 导出 SMILES)生成一个标准版本,再对照检查。不要完全相信自己的手写——人眼对数字配对很不敏感。
1.5 知识结构一览
为了让你对本章内容有个整体印象,我画了一个简单的流程图,展示从原始分子到 SMILES 字符串的转换逻辑,以及原子、键、分支、环各自扮演的角色。
1.6 关于跨批次一致性的第一个提醒
这一节我们只讨论了最基础的 SMILES 规则。但你在实际做跨批次分析时,很快就会遇到一个恼人的问题:同样的分子,第一周用 RDKit 2023.03 生成的 SMILES,和第三周用 RDKit 2024.09 生成的 SMILES,居然不一样!原因常常出在:
- 芳香性判定算法变化(比如之前把吡啶 N 判为芳香,新版判为非芳香)
- 环编号分配顺序不同(导致数字标记变了)
- 手性标记的 @ 或 @@ 方向(取决于输入坐标的顺序)
所以在开始任何跨批次项目前,我强烈建议你先定义一个“SMILES 标准化流水线”,固定解析器版本和参数。后面章节我们专门讲怎么搭这个流水线。
一个省事的做法:直接用 RDKit 的 MolToSmiles(mol, canonical=True) 生成规范字符串,然后对所有批次的 SMILES 都调用同一个函数重新标准化一次。这样至少保证同一分子在任何批次里的字符串完全一致。