# 自动接收主机名或标识前先拦非法字符：用 stringprep 表做协议字段预检

## 文档明确的机制

在自动化脚本读取配置、接口参数或外部系统标识时，主机名等字符串往往需要参与“相等性”比较，也可能需要被限制为可打印字符。Python 标准库文档说明，RFC 3454 定义了一种在互联网协议中“准备” Unicode 字符串的流程：字符串在发送到网络前经过处理，得到某种规范化形式。

需要先注意边界：`stringprep` 模块只暴露 RFC 3454 中的表，并不是一个替你决定协议规则的通用文本清洗库。RFC 的表可以组合成 profile；每个 profile 必须自行定义使用哪些表，以及 stringprep 流程中哪些可选部分属于该 profile。文档给出的例子是 `nameprep`，它用于国际化域名。因此，在没有协议 profile 依据时，脚本不能因为调用了若干表函数，就宣称输入符合 IDN、nameprep 或其他网络协议。

Python 文档还说明，这些表内部借助 Unicode 字符数据库实现，对外以函数而非字典或列表暴露。表分两类：

- **集合（sets）**：模块提供特征函数，参数属于该集合时返回 `True`。
- **映射（mappings）**：模块提供映射函数，给定码位返回对应值。

文档列出的集合函数可直接用于预检。例如：

- `in_table_a1(code)`：是否属于表 A.1，即 Unicode 3.2 中未赋值的码位。
- `in_table_c11(code)`、`in_table_c12(code)`、`in_table_c11_c12(code)`：分别检查 ASCII 空格、非 ASCII 空格及二者并集。
- `in_table_c21(code)`、`in_table_c22(code)`、`in_table_c21_c22(code)`：检查 ASCII 控制字符、非 ASCII 控制字符及二者并集。
- `in_table_c3(code)`：私用区字符。
- `in_table_c4(code)`：非字符码位。
- `in_table_c5(code)`：代理码位。
- `in_table_c6(code)` 至 `in_table_c9(code)`：不适合普通文本、不适合规范表示、改变显示属性或已弃用、标记字符等表。
- `in_table_d1(code)`、`in_table_d2(code)`：分别检查双向属性为“R”或“AL”、以及为“L”的字符。

映射方面，文档列出 `in_table_b1` 用于判断码位是否在 B.1“通常映射为空”的表中；`map_table_b2` 返回配合 NFKC 使用的大小写折叠映射，`map_table_b3` 返回不进行规范化时使用的大小写折叠映射。它们的含义应由目标 profile 决定，不能无条件视为“自动净化”。

## 团队自行约定的接手建议

以下是团队内部可采用的预检约定，不是 Python 文档声称的产品能力。

第一，把适用对象限定为**即将发送到网络协议或外部系统的 Unicode 标识**，例如配置文件中由外部填入、随后用于连接或标识资源的主机名。普通正文、用户备注、日志消息不应只因含空格、控制符或双向字符就被同一套规则拒绝。

第二，预检结果建议固定为三部分：

1. **通过或拒绝结论**；
2. **命中的 RFC 3454 表名及具体码位**；
3. **拒绝原因**，如“ASCII space”“Non-ASCII control”“Private use”“Surrogate codes”等文档已命名类别。

这样，接手者不必猜测字段为何被拒，也便于把失败输入转化为回归用例。

第三，在没有明确 profile 时，团队应把检查定位为“风险码位拦截”，而不是完整 stringprep 实现。可以针对字段风险选择表：面向协议标识时，优先记录空格、控制字符、私用区、非字符码位、代理码位及双向字符；是否映射 B.1、B.2、B.3，必须由所实现协议或团队明确规则决定。尤其是映射会改变输入，不应静默改写后再发送，除非协议 profile 要求并留下审计结果。

第四，双向字符建议只报告 D.1、D.2 命中情况和具体码位，由协议规则决定如何处理；文档列出的是字符属性表，并未替脚本定义完整双向处理算法。

## 边界与总结

`stringprep` 的版本边界同样重要。Python 文档明确把 A.1 描述为“Unicode 3.2 中未赋值的码位”，而 RFC 3454 的准备流程也处于该资料所述的 Unicode 版本语境中。因此，不能把这些检查解释为对当前任意 Unicode 版本、IDN 生态或具体应用协议合规性的最终证明。

还应区分三层事实：Python 模块暴露 RFC 3454 表函数；具体协议通过 profile 选择表和可选流程；团队脚本只是在协议字段发送前，用这些函数形成可观察的拒绝结论和证据。`nameprep` 是文档给出的 profile 示例，并不意味着任意主机名检查都等同 nameprep，也不意味着已经符合 IDN。

综上，自动接收主机名或其他标识时，可把 `stringprep` 用作码位级预检工具：逐码位识别未赋值、空格、控制字符、私用区、代理码位、双向字符等风险，并输出表名、码位和原因。但是否允许映射、规范化或拒绝某类字符，必须回到目标协议的 profile；团队约定只能补充工程交接格式，不能代替标准本身。

## 相关工具

[AI 工作流 ROI 诊断器](/demos/ai-workflow-roi-diagnostic/index.html) · 查看工具的输入要求、输出说明与适用范围。


来源：[自动接收主机名或标识前先拦非法字符：用 stringprep 表做协议字段预检](https://docs.python.org/3/library/stringprep.html)
