将字符串表示的二进制转换为浮点数。

huangapple go评论74阅读模式
英文:

Go convert to float from string which represent binary

问题

获取并转换Go gRPC元数据中的值。

在我的日志中,我发现元数据被转换为另一种类型(我认为是字节数组),如下所示:

"latitude-bin":"\ufffd\u0019\u0014\ufffd\ufffdϑL","longitude-bin":"@Z\ufffd\ufffd\ufffd\u000e\ufffdD"

如果我没有弄错的话,这两个值应该是Double类型的。
我想将这些值转换为Golang中的Doublefloat64,但是我对我的方法有些不确定,因为我不知道latitude-binlongitude-bin的类型,也无法重现这些值(从客户端的日志中获取)。

这是我的方法:

// GetLangitute从元数据`latitude-bin`中获取纬度,并在失败时返回nil
func GetLangitute(ctx context.Context) *float64 {
	metadataList := getMetaDataListByKey(ctx, latitudeBin)
	if metadataList != nil {
		s := metadataList[metadataIndex]
		b := []byte(s)
		// TODO: 
		// 我对这种方法还有些不确定
		data := math.Float64frombits(binary.BigEndian.Uint64(b))
		return &data
	}

	return nil
}

func getMetaDataListByKey(ctx context.Context, key string) []string {
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return nil
	}

	metadataList := md.Get(key)
	if isEmpty(metadataList) {
		return nil
	}

	return metadataList
}

func isEmpty(metadataList []string) bool {
	return len(metadataList) == 0
}

我尝试使用单元测试,看起来效果不错,但是由于无法重现预期结果,我仍然对结果有些不确定。这是我的单元测试:

f := math.Float64frombits(uint64(6662343813755067509))
// ...
name: "给定的键存在于元数据中",
			args: args{
				ctx: metadata.NewIncomingContext(
					context.Background(),
					metadata.Pairs("latitude-bin", `\ufffd\u0019\u0014\ufffd\ufffdϑL`),
				),
			},
			want: &f,
// ...
t.Run(tt.name, func(t *testing.T) {
	got := GetLangitute(tt.args.ctx)
	if tt.want != nil {
		if *got != *tt.want {
			t.Errorf("GetLangitute() = %v, want %v", got, tt.want)
		}
	} else {
		assert.Nil(t, got)
	}
})
英文:

Go gRPC metadata, get and convert the value.

In my logs, i saw that the metadata was being translated into another type (I think it's a byte array) like this

"latitude-bin":"\ufffd\u0019\u0014\ufffd\ufffdϑL","longitude-bin":"@Z\ufffd\ufffd\ufffd\u000e\ufffdD"

Both of those value should be a Double if I'm not mistaken.
I want to convert those value into a Double or float64 in Golang, but I'm a bit unsure about my approach, since I don't know the type of latitude-bin or longitude-bin and I can't reproduce those value (taken from the logs by my clients)

Here is my approach

// GetLangitute get latitude from metadata `latitude-bin` and return nil when fails
func GetLangitute(ctx context.Context) *float64 {
	metadataList := getMetaDataListByKey(ctx, latitudeBin)
	if metadataList != nil {
		s := metadataList[metadataIndex]
		b := []byte(s)
		// TODO: 
		// I'm still a bit unsure about this approach
		data := math.Float64frombits(binary.BigEndian.Uint64(b))
		return &data
	}

	return nil
}

func getMetaDataListByKey(ctx context.Context, key string) []string {
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return nil
	}

	metadataList := md.Get(key)
	if isEmpty(metadataList) {
		return nil
	}

	return metadataList
}

func isEmpty(metadataList []string) bool {
	return len(metadataList) == 0
}

I tried to test using a Unit Test and look good, but still I'm unsure about the expected result since I can't reproduce it, here is my Unit test

f := math.Float64frombits(uint64(6662343813755067509))
// ...
name: "Given key exist in metadata",
			args: args{
				ctx: metadata.NewIncomingContext(
					context.Background(),
					metadata.Pairs("latitude-bin", `\ufffd\u0019\u0014\ufffd\ufffdϑL`),
				),
			},
			want: &f,
// ...
t.Run(tt.name, func(t *testing.T) {
	got := GetLangitute(tt.args.ctx)
	if tt.want != nil {
		if *got != *tt.want {
			t.Errorf("GetLangitute() = %v, want %v", got, tt.want)
		}
	} else {
		assert.Nil(t, got)
	}
})

答案1

得分: 2

很不幸,看起来你的输入JSON已经出现了问题。你的JSON中的纬度和经度值是8字节的值,但它们并不代表原始值。原始值已经丢失。

Go将字符串存储为它们的UTF-8编码字节序列。当将其他类型转换为字符串(例如int)时,如果遇到无效值,转换将导致Unicode替换字符0xFFFD

你的输入包含多个这样的符文:\ufffd。这意味着生成你的输入JSON的编码算法有问题,导致信息丢失。很难恢复原始的纬度和经度值。

你必须修复源代码中的编码部分。

注意:如果你的输入是有效/正确的,你可以简单地将string值转换为[]byte,像这样:

b := []byte(s)

上述转换将得到s的字节,无论s是否包含有效的UTF-8序列。

英文:

Unfortunately it seems your input JSON is already "screwed". Your latitude and longitude values in JSON are 8-byte values, but they don't represent the original values. The original value is lost.

Go stores strings as their UTF-8 encoded byte sequence. When converting other types to string (e.g. int), when invalid values are encountered, the conversion will result in the Unicode replacement character 0xFFFD.

Your input contains multiple of these runes: \ufffd. This means the encoding algorithm that produces your input JSON is faulty and resulted in information loss. It's unlikely you can reproduce the original latitude and longitude values.

You must fix the encoding part of your source.

Note: if your input would be valid / correct, you could simply convert the string value to []byte like this:

b := []byte(s)

The above conversion would result in the bytes of s, regardless whether s contains valid UTF-8 sequence or not.

huangapple
  • 本文由 发表于 2021年8月9日 15:56:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/68708631.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定