解码自定义编码算法

问题描述 投票:0回答:1

我在Go中有以下自定义编码算法(类似于Base64)

func shuffle(input rune) rune {
    switch {
    case input > 37:
        return input + 59
    case input > 11:
        return input + 53
    case input > 1:
        return input + 46
    default:
        return 50*input + 45
    }
}

func customEncode(input []byte) string {
    inputLen := len(input)
    output := make([]rune, 0, inputLen*4)

    for i := 0; i < inputLen; i += 3 {
        var chunk uint32
        for j := 0; j < 3; j++ {
            shift := uint(16 - j*8)
            if i+j < inputLen {
                chunk |= uint32(input[i+j]) << shift
            } else {
                chunk |= uint32(0) << shift
            }
        }

        output = append(output,
            shuffle(rune((chunk>>18)&63)),
            shuffle(rune((chunk>>12)&63)),
            shuffle(rune((chunk>>6)&63)),
            shuffle(rune((chunk)&63)),
        )
    }

    inputLenMod3 := inputLen % 3
    
    if inputLenMod3 == 1 {
        output = output[:len(output)-2]
    } else if inputLenMod3 == 2 {
        output = output[:len(output)-1]
    }

    stringOutput := string(output)

    return stringOutput
}

我正在尝试为编码器编写一个解码器,这是我迄今为止的尝试:

func unshuffle(input rune) rune {
    switch {
    case input > 95:
        return input - 59
    case input > 69:
        return input - 53
    case input > 49:
        return input - 46
    default:
        return (input + 45) / 50
    }
}

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 := "LoremipsLoremips"
    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: H4xmNKpdQ5BAPr7ZPKZkQk
//[76 111 114 101 109 105 112 115 76 111 114 101 109 105 112 115]
//[76 111 114 101 109 105 112 117 19 111 114 101 109 105 112 115]
//--- FAIL: TestEncoding (0.00s)

从测试结果可以看出,输出字节与输入字节略有不同。我不确定我做错了什么 - 但如何修复解码器以确保输出与输入字节匹配?

有趣的是,如果我使用

Lorem
作为输入字符串,解码后的字节是正确的。

go
1个回答
0
投票

我没有花任何精力去理解你的算法;这是基于我在浏览代码时发现的一个问题的快速答案(很可能还有其他问题!)。

看起来

customEncode
将 3 个字节转换为 4 个字节(每个字节的值在 0 到 63 之间 - 这是基于
&63
的),然后将这些值传递给
shuffle
。让我们测试您的
shuffle
函数的这些值:

func main() {
    for i := 0; i <= 63; i++ {
        processed := unshuffle(shuffle(rune(i)))
        if rune(i) != processed {
            fmt.Println(i)
        }
    }
}

这将输出以下内容(playground):

0
1
2
3
12
13
14
15
16

看来你有一个错误。看看你的

shuffle
函数,我注意到超过
11
的值会增加
53
(意味着结果将超过
65
)。然而,在
unshuffle
中,您正在寻找
case input > 69
。如果我们解决这个问题(以及其他比较中的类似问题):


func shuffle(input rune) rune {
    switch {
    case input > 37:
        return input + 59
    case input > 11:
        return input + 53
    case input > 1:
        return input + 46
    default:
        return input + 45
    }
}

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
    }
}

测试有效playground(请注意,我还删除了

* 50
案例中的
default
,因为这看起来是错误的)。通过这些更改,您的测试也通过了(但值得使用随机序列进行测试(例如)。请注意,我不能保证输出正确,因为我只考虑了您确定的单个问题。

© www.soinside.com 2019 - 2024. All rights reserved.