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 字符串的转换逻辑,以及原子、键、分支、环各自扮演的角色。

SMILES 字符串构建逻辑 原始分子(2D/3D) 解析出: 原子 & 键 分支(括号) 环(数字) 组合成线性字符串 规范 SMILES(最终输出) ⚠ 跨批次一致性分析的关键:同一分子在不同工具、不同版本下的规范 SMILES 可能不同。 必须提前约定好解析器(如 RDKit 2024.09)和参数(如芳香性模型、手性规则)。

1.6 关于跨批次一致性的第一个提醒

这一节我们只讨论了最基础的 SMILES 规则。但你在实际做跨批次分析时,很快就会遇到一个恼人的问题:同样的分子,第一周用 RDKit 2023.03 生成的 SMILES,和第三周用 RDKit 2024.09 生成的 SMILES,居然不一样!原因常常出在:

  • 芳香性判定算法变化(比如之前把吡啶 N 判为芳香,新版判为非芳香)
  • 环编号分配顺序不同(导致数字标记变了)
  • 手性标记的 @ 或 @@ 方向(取决于输入坐标的顺序)

所以在开始任何跨批次项目前,我强烈建议你先定义一个“SMILES 标准化流水线”,固定解析器版本和参数。后面章节我们专门讲怎么搭这个流水线。

一个省事的做法:直接用 RDKit 的 MolToSmiles(mol, canonical=True) 生成规范字符串,然后对所有批次的 SMILES 都调用同一个函数重新标准化一次。这样至少保证同一分子在任何批次里的字符串完全一致。