Golang:验证字符串是否为有效的十六进制字符串?

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

Golang: verify that string is a valid hex string?

问题

我有一个结构体:

type Name struct {
    hexID string
    age uint8
}

最简单的方法是检查hexID字段是否是有效的十六进制字符串。如果不是,则引发错误。

例如:

var n Name
n.hexID = "Hello World >)" // 不是有效的十六进制
n.hexID = "aaa12Eb9990101010101112cC" // 有效的十六进制

或者可能存在结构体tag的地方吗?

英文:

I have a struct:

type Name struct {
    hexID string
    age uint8
}

What is the easiest way to check that hexID field is a valid hex string? And if not - rise an error.

For example:

var n Name
n.hexID = "Hello World >)" // not a valid hex
n.hexID = "aaa12Eb9990101010101112cC" // valid hex

Or maybe there are somewhere struct tag exists?

答案1

得分: 2

迭代字符串的每个字符,并检查每个字符是否是有效的十六进制数字。

func isValidHex(s string) bool {
    for _, r := range s {
        if !(r >= '0' && r <= '9' || r >= 'a' && r <= 'f' || r >= 'A' && r <= 'F') {
            return false
        }
    }
    return true
}

进行测试:

fmt.Println(isValidHex("Hello World >)"))
fmt.Println(isValidHex("aaa12Eb9990101010101112cC"))

输出结果(在Go Playground上尝试):

false
true

注意:你可能会尝试使用hex.DecodeString()并检查返回的错误:如果为nil,则表示有效。但请注意,该函数期望字符串的长度为偶数(因为它从十六进制数字生成字节,而2个十六进制数字形成一个字节)。更不用说,如果你不需要结果(作为字节切片),这种方法会更慢并且会产生不必要的垃圾(需要垃圾回收)。

另一种解决方案是使用big.Int.SetString()

func isValidHex(s string) bool {
    _, ok := new(big.Int).SetString(s, 16)
    return ok
}

这将输出相同的结果,在Go Playground上尝试。但这种方法仍然较慢并且会使用内存分配(生成垃圾)。

英文:

Iterate over the characters of the string, and check if each is a valid hex digit.

func isValidHex(s string) bool {
	for _, r := range s {
		if !(r &gt;= &#39;0&#39; &amp;&amp; r &lt;= &#39;9&#39; || r &gt;= &#39;a&#39; &amp;&amp; r &lt;= &#39;f&#39; || r &gt;= &#39;A&#39; &amp;&amp; r &lt;= &#39;F&#39;) {
			return false
		}
	}
	return true
}

Testing it:

fmt.Println(isValidHex(&quot;Hello World &gt;)&quot;))
fmt.Println(isValidHex(&quot;aaa12Eb9990101010101112cC&quot;))

Output (try it on the Go Playground):

false
true

Note: you'd be tempted to use hex.DecodeString() and check the returned error: if it's nil, it's valid. But do note that this function expects that the string has even length (as it produces bytes from the hex digits, and 2 hex digits forms a byte). Not to mention that if you don't need the result (as a byte slice), this is slower and creates unnecessary garbage (for the gc to collect).

Another solution could be using big.Int.SetString():

func isValidHex(s string) bool {
	_, ok := new(big.Int).SetString(s, 16)
	return ok
}

This outputs the same, try it on the Go Playground. But this again is slower and uses memory allocations (generates garbage).

答案2

得分: 2

不同的实现具有不同的性能。例如,

func isHexRock(s string) bool {
    for _, b := range []byte(s) {
        if !(b >= '0' && b <= '9' || b >= 'a' && b <= 'f' || b >= 'A' && b <= 'F') {
            return false
        }
    }
    return true
}

func isHexIcza(s string) bool {
    for _, r := range s {
        if !(r >= '0' && r <= '9' || r >= 'a' && r <= 'f' || r >= 'A' && r <= 'F') {
            return false
        }
    }
    return true
}

var rxNotHex = regexp.MustCompile("[^0-9A-Fa-f]")

func isHexOjacoGlobal(s string) bool {
    return !rxNotHex.MatchString(s)
}

func isHexOjacoLocal(s string) bool {
    notHex, err := regexp.MatchString("[^0-9A-Fa-f]", s)
    if err != nil {
        panic(err)
    }
    return !notHex
}

一些基准测试结果:

BenchmarkRock-4         36386997    30.92 ns/op     0 B/op   0 allocs/op
BenchmarkIcza-4         21100798    52.86 ns/op     0 B/op   0 allocs/op
BenchmarkOjacoGlobal-4   5958829   209.9 ns/op      0 B/op   0 allocs/op
BenchmarkOjacoLocal-4     227672  4648 ns/op     1626 B/op  22 allocs/op
英文:

> Comment: I'm completely confused now which one to use Golang:验证字符串是否为有效的十六进制字符串? – armaka


Different inplementations have different performance. For example,

func isHexRock(s string) bool {
    for _, b := range []byte(s) {
        if !(b &gt;= &#39;0&#39; &amp;&amp; b &lt;= &#39;9&#39; || b &gt;= &#39;a&#39; &amp;&amp; b &lt;= &#39;f&#39; || b &gt;= &#39;A&#39; &amp;&amp; b &lt;= &#39;F&#39;) {
            return false
        }
    }
    return true
}

func isHexIcza(s string) bool {
    for _, r := range s {
        if !(r &gt;= &#39;0&#39; &amp;&amp; r &lt;= &#39;9&#39; || r &gt;= &#39;a&#39; &amp;&amp; r &lt;= &#39;f&#39; || r &gt;= &#39;A&#39; &amp;&amp; r &lt;= &#39;F&#39;) {
            return false
        }
    }
    return true
}

var rxNotHex = regexp.MustCompile(&quot;[^0-9A-Fa-f]&quot;)

func isHexOjacoGlobal(s string) bool {
    return !rxNotHex.MatchString(s)
}

func isHexOjacoLocal(s string) bool {
    notHex, err := regexp.MatchString(&quot;[^0-9A-Fa-f]&quot;, s)
    if err != nil {
        panic(err)
    }
    return !notHex
}

Some benchmark results:

BenchmarkRock-4         36386997    30.92 ns/op     0 B/op   0 allocs/op
BenchmarkIcza-4         21100798    52.86 ns/op     0 B/op   0 allocs/op
BenchmarkOjacoGlobal-4   5958829   209.9 ns/op      0 B/op   0 allocs/op
BenchmarkOjacoLocal-4     227672  4648 ns/op     1626 B/op  22 allocs/op

答案3

得分: 1

这是要翻译的内容:

这个正则表达式用于判断字符串中是否包含非法的十六进制字符。

英文:

What about this one

regexp.MatchString(&quot;[^0-9A-Fa-f]&quot;, n.hexID)

True if string contains HEX illegal characters

答案4

得分: 0

我认为ParseInt方法也可以解决这个问题 -

    _, err := strconv.ParseInt("deadbeef", 16, 64)
    if err != nil {
       fmt.Println("不是一个十六进制字符串")
    } else {
    fmt.Println("是一个十六进制字符串")
  }
英文:

I think ParseInt method can also tackle this -

    _, err := strconv.ParseInt(&quot;deadbeef&quot;, 16, 64)
    if err != nil {
       fmt.Println(&quot;not a hex string&quot;)
    } else {
    fmt.Println(&quot;it is a hex string&quot;)
  }

huangapple
  • 本文由 发表于 2023年1月18日 17:39:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75157193.html
匿名

发表评论

匿名网友

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

确定