修复Go语言自定义Base64风格编码解码器的不匹配问题
自定义Base64风格编解码器的修复方案
问题背景
现有一个不可修改的Go语言自定义编码器(类似Base64),需要修复配套解码器,使其能正确还原原始输入字节。
给定的编码器代码
func shuffle(input rune) rune { return input + 59 } func customEncode(input []byte) string { inputLen := len(input) output := make([]rune, 0, inputLen*4/3*4) for i := 0; i < inputLen; i += 3 { chunk := uint32(0) for j := 0; j < 3; j++ { if i+j < inputLen { chunk |= uint32(input[i+j]) << (8 * (2 - j)) } } for shift := 18; shift >= 0; shift -= 6 { group := (chunk >> shift) & 63 output = append(output, shuffle(rune(group))) } } switch inputLen % 3 { case 1: output = output[:len(output)-2] case 2: output = output[:len(output)-1] } return string(output) }
当前错误的解码器代码
func unshuffle(input rune) rune { switch { case input > 96: return input - 59 case input > 64: return input - 53 case input > 47: return input - 46 default: return input - 45 } } func customDecode(encoded string) []byte { output := make([]byte, 0, len(encoded)) for i := 0; i < len(encoded); i += 4 { chunk := uint32(0) for j := 0; j < 4 && i+j < len(encoded); j++ { chunk |= uint32(unshuffle(rune(encoded[i+j]))) << (18 - j*6) } output = append(output, byte((chunk>>16)&0xFF), byte((chunk>>8)&0xFF), byte(chunk&0xFF), ) } if len(encoded)%4 == 3 { output = output[:len(output)-1] } else if len(encoded)%4 == 2 { output = output[:len(output)-2] } return output }
测试代码及错误结果
func TestEncoding(t *testing.T) { input := "Lorem ipsum" encoded := customEncode([]byte(input)) decoded := customDecode(encoded) fmt.Println(fmt.Sprintf("Encoded: %s", encoded)) fmt.Println([]byte(input)) fmt.Println(decoded) if !bytes.Equal([]byte(input), decoded) { t.Fail() } } // 错误输出: // Encoded: [符合group+59规则的字符串,而非测试中给出的H4xmNKoUOL_nRKo] // [76 111 114 101 109 32 105 112 115 117 109] // [76 111 114 101 109 32 105 122 179 117 109]
错误原因分析
核心问题是**unshuffle函数与编码器的shuffle逻辑不匹配**:
编码器的shuffle是直接将0-63的group值加59,而当前解码器的unshuffle错误地分情况减去不同数值,导致group值还原错误,进而生成错误的原始字节。
此外,输出切片的初始容量预估不合理,可优化为更符合Base64类编码的比例。
修改后的解码器代码
func unshuffle(input rune) rune { // 与编码器shuffle完全逆操作:直接减59 return input - 59 } func customDecode(encoded string) []byte { // 优化初始容量:4个编码字符对应3个原始字节 output := make([]byte, 0, len(encoded)*3/4) for i := 0; i < len(encoded); i += 4 { chunk := uint32(0) for j := 0; j < 4 && i+j < len(encoded); j++ { group := unshuffle(rune(encoded[i+j])) // 对应编码器的shift顺序:18,12,6,0 chunk |= uint32(group) << (18 - j*6) } // 提取三个原始字节 output = append(output, byte((chunk>>16)&0xFF), byte((chunk>>8)&0xFF), byte(chunk&0xFF), ) } // 根据编码长度调整输出,与编码器逻辑对应 switch len(encoded) % 4 { case 2: // 对应输入长度%3=1,解码后去掉最后2个无效字节 output = output[:len(output)-2] case 3: // 对应输入长度%3=2,解码后去掉最后1个无效字节 output = output[:len(output)-1] } return output }
修改说明
- 修复
unshuffle逻辑:直接返回input-59,与编码器的shuffle函数完全对应,确保group值正确还原。 - 优化初始容量:使用
len(encoded)*3/4作为输出切片的初始容量,更贴合编码比例,减少内存扩容开销。 - 保留正确的移位与长度调整逻辑:这部分逻辑原本与编码器匹配,无需修改。
修改后,解码器可正确还原所有输入字节,测试将通过。
注:当前测试中给出的Encoded字符串(H4xmNKoUOL_nRKo)与给定的编码器代码不兼容(包含小于59的ASCII字符,无法通过
group+59生成),推测是混淆了不同版本的编码器代码,需以给定的编码器代码为准进行测试。
内容的提问来源于stack exchange,提问作者Jake Evans
相关产品推荐
相关产品推荐

