This commit is contained in:
arraykeys
2019-08-08 17:13:34 +08:00
parent e8e5966a8c
commit f0bf2d5fec
2885 changed files with 1195993 additions and 12 deletions
@@ -0,0 +1,8 @@
// Copyright 2014 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.
// 一些常用的验证函数
package validator
const Version = "0.1.0.140928"
@@ -0,0 +1,68 @@
// Copyright 2014 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.
package validator
// 我国现行的身份证号码有两种标准:GB11643-1989、GB11643-1999
//
// GB11643-1989为一代身份证,从左至右分别为:
// ------------------------------------------------------------
// | 6位行政区域代码 | 6位出生年日期(不含世纪数)| 3位顺序码 |
// ------------------------------------------------------------
//
// GB11643-1999为二代身份证,从左至右分别为:
// ------------------------------------------------------------
// | 6位行政区域代码 | 8位出生日期 | 3位顺序码 | 1位检验码 |
// ------------------------------------------------------------
var (
// 校验位对应的规则。
gb11643Map = []byte{'1', '0', 'x', '9', '8', '7', '6', '5', '4', '3', '2'}
// 前17位号码对应的权值,为一个固定数组。可由gb11643_test.getWeight()计算得到。
gb11643Weight = []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
)
// 判断一个身份证是否符合gb11643标准。
// 若是15位则当作一代身份证,仅简单地判断各位是否都是数字;
// 若是18位则当作二代身份证,会计算校验位是否正确;
// 其它位数都返回false。
func IsGb11643(val interface{}) bool {
switch v := val.(type) {
case string:
return IsGb11643Bytes([]byte(v))
case []byte:
return IsGb11643Bytes(v)
case []rune:
return IsGb11643Bytes([]byte(string(v)))
default:
return false
}
}
// 判断一个身份证是否符合gb11643标准。
func IsGb11643Bytes(val []byte) bool {
if len(val) == 15 {
// 15位,只检测是否包含非数字字符。
for i := 0; i < 15; i++ {
if val[i] < '0' || val[i] > '9' {
return false
}
} // end for
return true
}
if len(val) != 18 {
return false
}
sum := 0
for i := 0; i < 17; i++ {
sum += (gb11643Weight[i] * int((val[i] - '0')))
}
if val[17] == 'X' {
val[17] = 'x'
}
return gb11643Map[sum%11] == val[17]
}
@@ -0,0 +1,99 @@
// Copyright 2014 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.
package validator
import (
"bytes"
)
// 有关ISBN的算法及其它相关内容,可参照http://zh.wikipedia.org/wiki/%E5%9B%BD%E9%99%85%E6%A0%87%E5%87%86%E4%B9%A6%E5%8F%B7
// 判断是否为合法的ISBN串号。可以同时判断ISBN10和ISBN13
func IsISBN(val interface{}) bool {
var result []byte
switch v := val.(type) {
case []byte:
result = v
case []rune:
result = []byte(string(v))
case string:
result = []byte(v)
default:
return false
}
if bytes.IndexByte(result, '-') > -1 {
result = eraseMinus(result)
}
switch len(result) {
case 10:
return isISBN10(result)
case 13:
return isISBN13(result)
default:
return false
}
}
// 判断是否为合法的ISBN10
func IsISBN10(val []byte) bool {
if bytes.IndexByte(val, '-') == -1 {
return isISBN10(val)
}
return isISBN10(eraseMinus(val))
}
// 判断是否为合法的ISBN13
func IsISBN13(val []byte) bool {
if bytes.IndexByte(val, '-') == -1 {
return isISBN13(val)
}
return isISBN13(eraseMinus(val))
}
// isbn10的校验位对应的值。
var isbn10Map = []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'x', '0'}
func isISBN10(val []byte) bool {
sum := 0
for i := 0; i < 9; i++ {
sum += int(val[i]-'0') * (10 - i)
}
if val[9] == 'X' {
val[9] = 'x'
}
return isbn10Map[11-sum%11] == val[9]
}
func isISBN13(val []byte) bool {
sum := 0
for i := 0; i < 12; i += 2 {
sum += int(val[i] - '0')
}
for i := 1; i < 12; i += 2 {
sum += (int(val[i]-'0') * 3)
}
return (10 - sum%10) == int(val[12]-'0')
}
// 过滤减号(-)符号
func eraseMinus(val []byte) []byte {
offset := 0
for k, v := range val {
if v == '-' {
offset += 1
continue
}
val[k-offset] = v
}
return val[0 : len(val)-offset]
}
@@ -0,0 +1,123 @@
// Copyright 2014 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.
package validator
import (
"regexp"
)
const (
// 匹配大陆电话
cnPhoneStr = `((\d{3,4})-?)?` + // 区号
`\d{7,8}` + // 号码
`(-\d{1,4})?` // 分机号,分机号的连接符号不能省略。
// 匹配大陆手机号码
cnMobileStr = `(0|\+?86)?` + // 匹配 0,86,+86
`(13[0-9]|` + // 130-139
`14[57]|` + // 145,147
`15[0-35-9]|` + // 150-153,155-159
`17[0678]|` + // 170,176,177,17u
`18[0-9])` + // 180-189
`[0-9]{8}`
// 匹配邮箱
emailStr = `[\w.-]+@[\w_-]+\w{1,}[\.\w-]+`
// 匹配IP4
ip4Str = `((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)`
// 匹配IP6,参考以下网页内容:
// http://blog.csdn.net/jiangfeng08/article/details/7642018
ip6Str = `(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|` +
`(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|` +
`(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|` +
`(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|` +
`(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|` +
`(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|` +
`(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|` +
`(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))`
// 同时匹配IP4和IP6
ipStr = "(" + ip4Str + ")|(" + ip6Str + ")"
// 匹配域名
domainStr = `[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9][a-zA-Z0-9_-]{0,62})*(\.[a-zA-Z][a-zA-Z0-9]{0,10}){1}`
// 匹配URL
urlStr = `((https|http|ftp|rtsp|mms)?://)?` + // 协议
`(([0-9a-zA-Z]+:)?[0-9a-zA-Z_-]+@)?` + // pwd:user@
"(" + ipStr + "|(" + domainStr + "))" + // IP或域名
`(:\d{1,4})?` + // 端口
`(/+[a-zA-Z0-9][a-zA-Z0-9_.-]*/*)*` + // path
`(\?([a-zA-Z0-9_-]+(=[a-zA-Z0-9_-]*)*)*)*` // query
)
func regexpCompile(str string) *regexp.Regexp {
return regexp.MustCompile("^" + str + "$")
}
var (
email = regexpCompile(emailStr)
ip4 = regexpCompile(ip4Str)
ip6 = regexpCompile(ip6Str)
ip = regexpCompile(ipStr)
url = regexpCompile(urlStr)
cnPhone = regexpCompile(cnPhoneStr)
cnMobile = regexpCompile(cnMobileStr)
)
// 判断val是否能正确匹配exp中的正则表达式。
// val可以是[]byte, []rune, string类型。
func isMatch(exp *regexp.Regexp, val interface{}) bool {
switch v := val.(type) {
case []rune:
return exp.MatchString(string(v))
case []byte:
return exp.Match(v)
case string:
return exp.MatchString(v)
default:
return false
}
}
// 验证中国大陆的电话号码。支持如下格式:
// 0578-12345678-1234
// 057812345678-1234
// 若存在分机号,则分机号的连接符不能省略。
func IsCnPhone(val interface{}) bool {
return isMatch(cnPhone, val)
}
// 验证中国大陆的手机号码
func IsCnMobile(val interface{}) bool {
return isMatch(cnMobile, val)
}
// 验证一个值是否标准的URL格式。支持IP和域名等格式
func IsURL(val interface{}) bool {
return isMatch(url, val)
}
// 验证一个值是否为IP,可验证IP4和IP6
func IsIP(val interface{}) bool {
return isMatch(ip, val)
}
// 验证一个值是否为IP6
func IsIP6(val interface{}) bool {
return isMatch(ip6, val)
}
// 验证一个值是滞为IP4
func IsIP4(val interface{}) bool {
return isMatch(ip4, val)
}
// 验证一个值是否匹配一个邮箱。
func IsEmail(val interface{}) bool {
return isMatch(email, val)
}
@@ -0,0 +1,60 @@
// Copyright 2014 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.
package validator
import (
"github.com/caixw/lib.go/assert"
)
// 判断一个[]byte变量是否可以转换成数值。
func IsNumberBytes(bs []byte) bool {
// 首位字符可以是[0-9.+-]
b := bs[0]
if (b < '0' && b > '9') && b != '+' && b != '-' && b != '.' {
return false
}
hasDot := (b == '.')
for _, b = range bs[1:] {
if (b < '0' || b > '9') && b != '.' {
return false
}
if b == '.' {
if hasDot { // 多个小数点
return false
}
hasDot = true
}
}
return true
}
// 判断一个值是否可转换为数值。不支持全角数值的判断。
// 允许带一个小数点及起始的正负号,但不允许千位分隔符什么的。
func IsNumber(val interface{}) bool {
switch v := val.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
return true
case []byte:
return IsNumberBytes(v)
case string:
return IsNumberBytes([]byte(v))
default:
return false
}
}
// 判断是否为空值。
// 具体参照githbu.com/caixw/lib.go/assert.IsEmtpy()
func IsEmpty(val interface{}) bool {
return assert.IsEmpty(val)
}
// 判断是否为Nil。
// 具体参照githbu.com/caixw/lib.go/assert.IsNil()
func IsNil(val interface{}) bool {
return assert.IsNil(val)
}