SMILES到分子图转换教程 - 第2节
第2章 SMILES语法基础:原子、键、括号规则
讲真,SMILES 的语法并没有你想象的那么复杂。说白了,它就是一套用 ASCII 字符 描述分子结构的规则。我当年刚接触计算化学时,第一反应是:这玩意儿能替代结构式?后来才意识到,正是这种简洁性,让它成了 Cheminformatics 领域的“通用语”。
咱们从最基础的规则说起。
2.1 原子表示:基础中的基础
SMILES 用元素符号的方括号形式来表示原子。但具体怎么写,有几个关键点。
- 常规有机元素:B、C、N、O、P、S、F、Cl、Br、I —— 这些可以直接写符号,不用加方括号。比如甲烷就是
C,乙醇是CCO。 - 其他元素:必须用方括号括起来,比如 [Fe]、[Au]、[Si]。我遇到过一个坑:当年解析一个含钨的配合物时,直接写了个 “W”,结果程序报错——钨是金属,得写成
[W]。 - 同位素与价态:方括号内可以带上数字和符号。比如
[13C]表示碳-13同位素,[Fe+2]表示二价铁离子。我曾经处理过一个含三价钴的配体,写成[Co+3]就对了。
为什么要区分?因为 SMILES 是个严格的语言——它不靠上下文猜。你写 C,它就知道是碳;你写 [C],它也知道是碳,但前者默认是四价有机环境,后者就是任意价态。
个人习惯:我一般只在处理非常规元素或需要指定同位素/电荷时,才用方括号。平时写有机分子,尽量用简写,代码更干净。
2.2 键类型:单键、双键、三键和芳香键
SMILES 里的键用一个或几个字符夹在两个原子之间表示。规则很简单:
| 键类型 | 符号 | 示例 | 含义 |
|---|---|---|---|
| 单键 | - |
C-C |
标准单键,可省略 |
| 双键 | = |
C=C |
碳碳双键 |
| 三键 | # |
C#C |
碳碳三键 |
| 芳香键 | : |
c1ccccc1 |
芳香环中的键 |
这里有个重要特性:单键可以省略不写。比如乙醇 CCO,中间没写 -,系统会自动理解为单键。但双键和三键不能省。
为什么会这样?其实是为了压缩字符串长度。RDKit 底层解析时,碰到连续的字母会尝试自动连键。我一开始写 SMILES 时总是把单键也写上,后来发现纯属多余。
注意:省略单键不等于省略连接关系。如果你写 CC,表示两个碳原子直接相连;如果你写 C C(中间加空格),那它就不是一个合法的 SMILES——因为空格不是原子也不是键。
2.3 分支与括号:处理复杂结构
分子结构往往不是线性的。SMILES 用括号 () 表示分支结构。规则如下:
- 分支写在括号里,插入到主链的对应位置。
- 括号内的原子从某一连接点分叉出去,然后还可以继续延伸或再接分支。
- 嵌套分支:括号里面可以再套括号。
举个例子,异丁醇的结构:
CC(C)CO
怎么理解?
- 从左往右读:C (主链第一个碳)。
- 接着是 C (第二个碳)。
- 然后是
(C)——表示在第二个碳这里分出一个甲基分支。 - 最后是
CO——主链继续延伸,连到醇羟基碳。
我曾经在解析一个复杂天然产物时,遇到7层嵌套分支。当时我手动写的 SMILES 漏了一个括号,结果 RDKit 怎么也解析不对。排查了好一阵才找到问题——少了个右括号。从那以后,我习惯用括号计数器来检查。
检查小技巧:SMILES 中的左右括号数必须相等。写完后数一下括号数量,能帮你避免很多低级错误。
2.4 环的表示:数字编号
环用数字标记表示开环和闭环。规则是:
- 用数字 1-9 标记环的开端和结束端。
- 相同数字出现两次:第一次表示开始,第二次表示结束。
- 多个环:可以用多个不同数字表示。
比如环己烷 C6H12,它的 SMILES 是:
C1CCCCC1
怎么解读?
- 第一个 C 后紧跟
1——标记第一个环开始。 - 接着是 5 个 C(CCCCC)。
- 最后一个 C 后紧跟
1——表示环闭合回到第一个标记点。
对于苯环,标准写法是 c1ccccc1(注意用小写字母表示芳香碳)。但 RDKit 也可以识别 C1=CC=CC=C1(用交替双键表示)。我个人推荐用芳香的写法——更符合化学直觉,而且后续的芳香性感知不会出错。
注意:一个数字在一条 SMILES 中最多出现两次。如果分子中有 10 个以上的环,需要用 %数字 格式(比如 %10、%11)。不过绝大多数有机分子用 1-9 就够了。
2.5 核心知识结构
下面这张图总结了 SMILES 语法的四个核心要素。你可以把它当成“解析路线图”来用。
嗯,到这里 SMILES 的核心语法基本就讲完了。你可能会觉得规则有点多,但其实就四个点:原子怎么写、键怎么标、分支怎么括、环怎么编号。把这些搞清楚了,80% 的有机分子你都能手写出来。
最后一个小建议:刚开始写 SMILES 时,可以用 RDKit 或在线解析器帮你验证。写完后,用 rdkit.Chem.MolFromSmiles() 跑一下,如果返回 None,就说明你写的东西有问题。我曾经靠这个工具逮到无数手误。