Day 026 — 图解:字符串高级
本目录包含 Day 026 主题相关的 ASCII 图和 Mermaid 图解。
正则表达式执行流程
NFA 引擎匹配过程
正则: a(b|c)d
文本: "abd"
引擎执行路径:
Step 1: a → 匹配 'a' ✅
↓
Step 2: (b|c) → 分支1: 尝试 'b' → 'b' 匹配 ✅ 选择 b
↓
Step 3: d → 匹配 'd' ✅
↓
匹配成功!
如果在分支1失败,回溯到分支2尝试 'c'。
这就是正则引擎的"回溯"机制。
贪婪 vs 非贪婪匹配路径
文本: "<div>a</div><div>b</div>"
贪婪模式: <div>(.*)</div>
<div>a</div><div>b</div>
^^^^^ → 匹配 <div>
^^^^^^^^^^^^^^^^^^ → .* 尽可能多匹配(贪心)
^^^^^^^ → 匹配最后的 </div>
结果: "a</div><div>b"
非贪婪模式: <div>(.*?)</div>
<div>a</div><div>b</div>
^^^^^ → 匹配 <div>
^ → .*? 尽可能少匹配(找到一个就停)
^^^^^^ → 匹配 </div>
结果: "a"
(继续搜索...)
字符编码转换流程
Python 的 str ↔ bytes 模型
┌─────────────────────────────────────────────────┐
│ 内存 (RAM) │
│ │
│ str = "你好世界" │
│ (Unicode 码点序列: U+4F60, U+597D, U+4E16, U+754C)│
└──────────────────────┬──────────────────────────┘
│
┌────────────┴────────────┐
│ str.encode('utf-8') │
│ bytes.decode('utf-8') │
└────────────┬────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ 磁盘/网络 │
│ │
│ bytes = b'\xe4\xbd\xa0\xe5\xa5\xbd...' │
│ (UTF-8 编码后的原始字节) │
└─────────────────────────────────────────────────┘
UTF-8 编码示意
字符: A 中 😊
码点: U+0041 U+4E2D U+1F60A
二进制: 1000001 100111000101101 11111011000001010
UTF-8 编码:
A (1字节, 0x00-0x7F):
0xxxxxxx
01000001 → 0x41
中 (3字节, 0x0800-0xFFFF):
1110xxxx 10xxxxxx 10xxxxxx
11100100 10111000 10101101 → 0xE4 0xB8 0xAD
😊 (4字节, 0x10000-0x10FFFF):
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
11110000 10011111 10011000 10001010 → 0xF0 0x9F 0x98 0x8A
Mermaid 图解(渲染后可见)
正则匹配流程
flowchart LR
A["输入字符串<br/>abc123def456"] --> B["正则引擎"]
B --> C{"尝试匹配<br/>r'\d+'"}
C -->|"位置0: 'a'<br/>不是数字"| D["前进到位置1"]
D -->|"位置1: 'b'<br/>不是数字"| E["前进到位置2"]
E -->|"位置2: 'c'<br/>不是数字"| F["前进到位置3"]
F -->|"位置3: '1' ✅<br/>位置4: '2' ✅<br/>位置5: '3' ✅<br/>位置6: 'd' ❌"| G["匹配成功<br/>'123'"]
G --> H{"继续搜索?"}
H -->|"是"| I["位置6继续..."]
I --> J["最终: ['123','456']"]
flowchart LR
A["输入字符串<br/>abc123def456"] --> B["正则引擎"]
B --> C{"尝试匹配<br/>r'\d+'"}
C -->|"位置0: 'a'<br/>不是数字"| D["前进到位置1"]
D -->|"位置1: 'b'<br/>不是数字"| E["前进到位置2"]
E -->|"位置2: 'c'<br/>不是数字"| F["前进到位置3"]
F -->|"位置3: '1' ✅<br/>位置4: '2' ✅<br/>位置5: '3' ✅<br/>位置6: 'd' ❌"| G["匹配成功<br/>'123'"]
G --> H{"继续搜索?"}
H -->|"是"| I["位置6继续..."]
I --> J["最终: ['123','456']"]
日志解析管道
graph LR
subgraph 输入
A["📄 原始日志文件<br/>每行一条记录"]
end
subgraph 解析层
B["🔍 正则匹配<br/>LOG_PATTERN.match(line)"]
C["🧹 数据清洗<br/>类型转换/去空"]
end
subgraph 分析层
D["📊 统计分析<br/>状态码/IP/时间"]
E["🔎 过滤查询<br/>按条件筛选"]
F["📈 趋势分析<br/>时间序列"]
end
subgraph 输出层
G["📋 JSON 结构化<br/>可序列化"]
H["📄 报告生成<br/>文本/HTML"]
I["💾 存储到数据库"]
end
A --> B --> C --> D
C --> E
C --> F
D --> G
D --> H
E --> H
F --> H
D --> I
graph LR
subgraph 输入
A["📄 原始日志文件<br/>每行一条记录"]
end
subgraph 解析层
B["🔍 正则匹配<br/>LOG_PATTERN.match(line)"]
C["🧹 数据清洗<br/>类型转换/去空"]
end
subgraph 分析层
D["📊 统计分析<br/>状态码/IP/时间"]
E["🔎 过滤查询<br/>按条件筛选"]
F["📈 趋势分析<br/>时间序列"]
end
subgraph 输出层
G["📋 JSON 结构化<br/>可序列化"]
H["📄 报告生成<br/>文本/HTML"]
I["💾 存储到数据库"]
end
A --> B --> C --> D
C --> E
C --> F
D --> G
D --> H
E --> H
F --> H
D --> I
字符编码发展历程
timeline
title 字符编码发展史
1960s : ASCII 诞生
: 7位编码, 128字符
: 只有英文字母和符号
1980s : 各国本地编码
: GB2312 (中国)
: Shift-JIS (日本)
: 互不兼容, 乱码频发
1991 : Unicode 1.0 发布
: 统一字符集 UCS
: 给每个字符一个码点
2000s : UTF-8 成为主流
: 变长编码, ASCII兼容
: 互联网/W3C 默认编码
2026 : Python 3 全面 Unicode
: str 内部 Unicode
: 绝大多数系统默认 UTF-8
timeline
title 字符编码发展史
1960s : ASCII 诞生
: 7位编码, 128字符
: 只有英文字母和符号
1980s : 各国本地编码
: GB2312 (中国)
: Shift-JIS (日本)
: 互不兼容, 乱码频发
1991 : Unicode 1.0 发布
: 统一字符集 UCS
: 给每个字符一个码点
2000s : UTF-8 成为主流
: 变长编码, ASCII兼容
: 互联网/W3C 默认编码
2026 : Python 3 全面 Unicode
: str 内部 Unicode
: 绝大多数系统默认 UTF-8