px普贤教程PuXian
普贤教程 › 生态包

标识与校验

生成唯一 ID、解析 ID、比较版本号——这 6 个包都不需要数据库、不需要中心服务,编译进二进制就能用。本页所有输出为本机实测。

四种 ID,四种取舍

包样例长度有序适用
uuidbace88f9-b996-457d-9399-6349c7afa70236否跨系统标识、幂等键
ulid01M6NHWAXKWRY7ZQRGDSVDT40M26是(时间前缀)主键(按时间自然排序)
nanoidKTN1f86tgiuAqO4MYJdIE21否短链接、分享码
snowflake198602402181627494419 位数字是(毫秒前缀)数据库 bigint 主键
px
import uuid
import ulid
import nanoid
import snowflake

print(uuid_v4())
print(uuid_valid(uuid_v4()))        # true
print(uuid_format(uuid_parse("bace88f9b996457d93996349c7afa702").ok()))   # 32 hex → 标准 36 位

print(ul_new())                     # 01M6NHWAXKWRY7ZQRGDSVDT40M
print(ul_ts(ul_new()).ok())         # 1793872243636  ← 毫秒时间戳

print(nd_generate(21).ok())         # KTN1f86tgiuAqO4MYJdIE

var sf = sf_new(7).ok()             # machine_id 0..1023
print(sf_next(sf, 1762340000000).ok())    # 1986024021816274944
print(sf_parse(1986024021816274944))      # {machine: 7, ms: 1762340000000, seq: 1}
snowflake 的坑:sf_next(sf) 不带时间会报错 sf_next(state, now_ms=null) 的参数名 now_ms 遮蔽了内建函数 now_ms(),函数体里再调 now_ms() 时拿到的是 null: 运行时错误 [sf_next 行24]: R1004: 值不可调用: null。 必须显式传毫秒时间戳:sf_next(sf, now_ms())(在外面先算好后传进去)。这与「自定义 def env(...) 会段错误」是同一类问题——参数名不要与内建函数同名。
ID 选型的经验值要「按时间排序又不想暴露业务量」→ ULID;要「数据库一列 long、索引友好」→ Snowflake;要「短、可放 URL」→ NanoID;要「跟外部系统对接」→ UUID。

版本号比较

px
import semver

print(sv_cmp("1.2.3", "1.2.10"))        # -1     ← 语义化比较,不是字符串比较
print(sv_satisfies("1.2.5", "^1.2.0"))  # true
print(sv_best(["1.2.0", "1.2.5", "2.0.0"], "^1.2.0"))   # 1.2.5
print(sv_parse("1.2.3-alpha.1+build5"))
# {major: 1, minor: 2, patch: 3, pre: alpha.1, build: build5, raw: …}

范围语法是 cargo/npm 风格:^ / ~ / 精确 / * / x 通配。pxpkg 自己的版本解析用的就是它。

别用字符串比较版本"1.2.10" > "1.2.9" 在字符串比较里是 false("1" < "9")。这类 bug 只会在 1.2.10 发布那天爆出来。

校验位

px
import luhn
print(luhn_valid("4539148803436467"))    # 银行卡号格式校验
print(luhn_append("453914880343646"))  # 补出校验位
print(luhn_card_type("4539148803436467"))  # visa

import checksum
print(crc32_hex("hello"))     # 3610a686   ← 与 zlib.crc32 一致
print(adler32("hello"))       # 103547413
print(crc32_hex(""))          # 00000000

checksum 是「一致性校验」不是「防篡改」:CRC32 用来发现传输损坏,要防篡改用 SHA-256(sha256_hex 内建,或 secure_random 同族的哈希)。

编码

px
import base58
print(base58_encode("Hello PuXian"))          # 2NEpo7TZRNNpwXZD7
print(base58_decode("2NEpo7TZRNNpwXZD7").ok())# Hello PuXian
print(base58check_encode("abc"))              # 4h3c6RH52R  ← 带 4 字节双 SHA-256 校验

import punycode
print(pd_encode("中文.cn"))                    # xn--fiq228c.cn

Base58 去掉了 0OIl 四个易混字符,适合人工抄录;Base58Check 加了校验位,抄错能立刻发现——比特币地址就是这么做的。

字段校验(与 auth 页互补)

px
import validator
print(val_validate({"email": "a@b.com", "age": 20},
                   {"email": "required|email", "age": "int_range=18,60"}))  # Ok(null)

规则见 认证与安全页。validator 管格式,luhn / idcard 管校验位,两者组合能挡住绝大多数「手滑输入」。