最可靠的方法是用 strconv.ParseUint(s, 16, 64),它严格校验非空、无非法字符、不超范围;需预处理去掉空格和“0x”前缀并统一大小写;若仅校验字符合法性,可用 strings.IndexFunc 遍历判断。

用 strconv.ParseUint 判断是否为纯十六进制字符串最可靠
直接用正则匹配 [0-9a-fA-F]+ 看似简单,但会漏掉空字符串、前导零异常、超长位数等边界问题。真正校验“是否只含合法十六进制字符且可被解释为有效整数”,strconv.ParseUint(s, 16, 64) 是标准做法——它内部做了完整合法性检查,包括非空、无非法字符、不超范围。
注意:它要求字符串非空,且不能有前导空格或 0x 前缀(除非你手动去掉):
- 空字符串
""→ 返回错误 -
"0x1a"→ 返回错误(必须手动截掉"0x") -
"123g"→ 返回错误(g非法) -
"0000"→ 成功(合法)
需要忽略大小写和前缀时先做预处理
如果输入可能带 "0x" 或 "0X" 前缀,或混合大小写,别在正则里硬拼,先标准化再解析:
- 用
strings.TrimSpace(s)去首尾空格 - 用
strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X")判断并切掉前缀 - 用
strings.ToLower(s)统一小写(可选,ParseUint本身支持大小写,但统一后更可控) - 再传给
strconv.ParseUint(..., 16, 64)
示例:ParseUint("0XFF", 16, 64) 会失败,必须先处理成 "FF"。
立即学习“go语言免费学习笔记(深入)”;
只校验字符合法性(不要求可转整数)用 strings.IndexFunc 更轻量
如果你只是想快速判断“每个字符都在 0-9a-fA-F 范围内”,不关心是否为空或是否能转成数字,用 strings.IndexFunc 比正则快、比 ParseUint 开销小:
func isHexOnly(s string) bool {
if s == "" {
return false
}
for _, r := range s {
if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F')) {
return false
}
}
return true
}
这个函数不依赖任何包,也不分配内存,适合高频调用场景。但注意它不会拒绝 "00000000000000000000..." 这种超长串——而 ParseUint 会在解析时自然截断或报错。
别用 regexp.MustCompile(`^[0-9a-fA-F]+$`) 做生产校验
正则能匹配字符集,但掩盖了真实需求差异:
- 它接受
"0"和"00",但某些协议可能要求偶数长度(如 hex 编码 byte) - 它接受空字符串(
^$匹配空),而多数业务场景下空 hex 无效 - 它无法区分
"ff"和"0xff"—— 后者对人类友好,但不是纯 hex 字符串 - 编译正则有初始化开销,且每次调用都涉及回溯匹配,性能不如上面两种方案
除非你明确只要“字符集合校验”,且已控制输入来源(比如前端已过滤过),否则别把它当默认解法。
真正容易被忽略的是:hex 字符串的语义依赖上下文。是表示一个整数?还是表示字节序列?前者要走 ParseUint,后者可能得用 hex.DecodeString 并检查错误——后者还额外要求长度为偶数。


















