Golang中如何指定字符串类型/格式
Golang中如何指定字符串类型/格式 你好,我正在创建一个程序,它接收用户输入的主机名。如你所知,主机名的格式类似于 server.hostname.com。
因此,我希望在主机名无效时程序能退出。
例如,如果客户输入了 1、hello、domain.com 或 example.com,程序将退出;而如果客户输入了正确的主机名,如 server.server.com、vps.mydomain.com 等,程序将输出正确。
对此有什么想法吗?
3 回复
在什么确切条件之后才有效?hello 对我来说看起来像是一个正确的主机名……同样,example.com 也是如此……
更多关于Golang中如何指定字符串类型/格式的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我不太清楚你所说的“有效”具体指什么。我认为你可能对主机名的概念有些困惑。在你的例子中,看起来你可能是想要“包含子域名、二级域名和顶级域名”。一般来说,我认为 net/url 包是你需要的。下面的代码:
package main
import (
"fmt"
"log"
"net/url"
"strings"
)
func main() {
testCases := []string{"server.hostname.com", "server.hostname.com:443/?q=asdf", "1", "hello", "domain.com", "123.asd.xyz", "has space in it"}
for _, h := range testCases {
validateHost(h)
validateSubdomain(h)
}
}
func validateHost(hn string) {
u := parseURI(hn)
if len(u.Host) > 0 {
// 可以尝试改为 u.Hostname() 来去除端口号...
fmt.Println(u.Host, "is a valid host name")
}
}
func validateSubdomain(hn string) {
u := parseURI(hn)
if strings.Count(u.Host, ".") == 2 {
fmt.Println(u.Host, "contains sub, second-level, and top level domain")
}
}
func parseURI(hn string) *url.URL {
// 将方案硬编码为 https
u, err := url.Parse("https://" + hn)
if err != nil {
log.Fatal(err)
}
return u
}
https://play.golang.org/p/y0Hr43XteiN
… 将会得到:
server.hostname.com is a valid host name
server.hostname.com contains sub, second-level, and top level domain
server.hostname.com:443 is a valid host name
server.hostname.com:443 contains sub, second-level, and top level domain
1 is a valid host name
hello is a valid host name
domain.com is a valid host name
123.asd.xyz is a valid host name
123.asd.xyz contains sub, second-level, and top level domain
2009/11/10 23:00:00 parse "https://has space in it": invalid character " " in host name
… 这应该足够帮助你开始了。
在Go中,可以通过正则表达式验证主机名格式。以下是一个示例实现:
package main
import (
"fmt"
"os"
"regexp"
)
func isValidHostname(hostname string) bool {
// 主机名正则规则:
// 1. 由点分隔的多个标签组成
// 2. 每个标签以字母或数字开头和结尾
// 3. 标签内可包含字母、数字、连字符
// 4. 标签长度1-63字符
// 5. 总长度不超过253字符
pattern := `^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`
if len(hostname) > 253 {
return false
}
matched, err := regexp.MatchString(pattern, hostname)
if err != nil {
return false
}
return matched
}
func main() {
// 测试用例
testCases := []string{
"1",
"hello",
"domain.com",
"example.com",
"server.server.com",
"vps.mydomain.com",
"valid-host.example.com",
"-invalid.com",
"invalid-.com",
"this-label-is-way-too-long-for-a-hostname-label.example.com",
}
for _, hostname := range testCases {
if isValidHostname(hostname) {
fmt.Printf("✓ 有效: %s\n", hostname)
} else {
fmt.Printf("✗ 无效: %s\n", hostname)
}
}
// 实际使用示例
var input string
fmt.Print("请输入主机名: ")
fmt.Scanln(&input)
if !isValidHostname(input) {
fmt.Println("错误: 无效的主机名格式")
os.Exit(1)
}
fmt.Printf("主机名 %s 有效\n", input)
}
对于更严格的验证,可以使用net包的内置函数:
package main
import (
"fmt"
"net"
"os"
"strings"
)
func isValidHostnameStrict(hostname string) bool {
// 移除可能的端口号
hostname = strings.Split(hostname, ":")[0]
// 使用net.LookupHost验证
_, err := net.LookupHost(hostname)
if err != nil {
// 尝试作为域名解析
_, err = net.LookupAddr(hostname)
return err == nil
}
return true
}
func main() {
hostnames := []string{
"google.com",
"invalid-hostname-12345.com",
"localhost",
"192.168.1.1",
}
for _, hostname := range hostnames {
if isValidHostnameStrict(hostname) {
fmt.Printf("可解析: %s\n", hostname)
} else {
fmt.Printf("不可解析: %s\n", hostname)
}
}
}
如果需要同时验证格式和解析性:
package main
import (
"fmt"
"net"
"os"
"regexp"
"strings"
)
func validateHostname(hostname string) error {
// 基础格式验证
pattern := `^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`
if len(hostname) > 253 {
return fmt.Errorf("主机名长度超过253字符")
}
matched, _ := regexp.MatchString(pattern, hostname)
if !matched {
return fmt.Errorf("主机名格式无效")
}
// 尝试解析
hostname = strings.Split(hostname, ":")[0]
_, err := net.LookupHost(hostname)
if err != nil {
return fmt.Errorf("主机名无法解析: %v", err)
}
return nil
}
func main() {
var input string
fmt.Print("输入主机名: ")
fmt.Scanln(&input)
if err := validateHostname(input); err != nil {
fmt.Printf("错误: %v\n", err)
os.Exit(1)
}
fmt.Println("主机名验证通过")
}
这些示例提供了不同严格程度的验证方法,可根据实际需求选择使用。

