feat[golang]: 添加一些go的常用工具类

This commit is contained in:
godotg committed 2022-09-16 11:37:02 +08:00
1 parent 0c4029ffad
commit 180906e577
24 files changed
+2420

No files matched your search

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package assert
import "testing"
// Equalf asserts that two objects are equal.
//
// assert.Equalf(t, 123, 123, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equalf(t *testing.T, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
t.Helper()
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// NotEqualf asserts that the specified values are NOT equal.
//
// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqualf(t *testing.T, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
t.Helper()
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Nilf asserts that the specified object is nil.
//
// assert.Nilf(t, err, "error message %s", "formatted")
func Nilf(t *testing.T, object interface{}, msg string, args ...interface{}) bool {
t.Helper()
return Nil(t, object, append([]interface{}{msg}, args...)...)
}
// NotNilf asserts that the specified object is not nil.
//
// assert.NotNilf(t, err, "error message %s", "formatted")
func NotNilf(t *testing.T, object interface{}, msg string, args ...interface{}) bool {
t.Helper()
return NotNil(t, object, append([]interface{}{msg}, args...)...)
}
// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// assert.Emptyf(t, obj, "error message %s", "formatted")
func Emptyf(t *testing.T, object interface{}, msg string, args ...interface{}) bool {
t.Helper()
return Empty(t, object, append([]interface{}{msg}, args...)...)
}
// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
// assert.Equal(t, "two", obj[1])
// }
func NotEmptyf(t *testing.T, object interface{}, msg string, args ...interface{}) bool {
t.Helper()
return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
}
// Lenf asserts that the specified object has specific length.
// Lenf also fails if the object has a type that len() not accept.
//
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
func Lenf(t *testing.T, object interface{}, length int, msg string, args ...interface{}) bool {
t.Helper()
return Len(t, object, length, append([]interface{}{msg}, args...)...)
}
+311
View File
@@ -0,0 +1,311 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package assert
import (
"bufio"
"bytes"
"errors"
"fmt"
"reflect"
"strings"
"testing"
"time"
)
// Equal asserts that two objects are equal.
//
// assert.Equal(t, 123, 123)
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equal(t *testing.T, expected, actual interface{}, msgAndArgs ...interface{}) bool {
t.Helper()
if err := validateEqualArgs(expected, actual); err != nil {
return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
expected, actual, err), msgAndArgs...)
}
if !ObjectsAreEqual(expected, actual) {
expected, actual = formatUnequalValues(expected, actual)
return Fail(t, fmt.Sprintf("Not equal: \n"+
"expected: %s\n"+
"actual : %s", expected, actual), msgAndArgs...)
}
return true
}
// NotEqual asserts that the specified values are NOT equal.
//
// assert.NotEqual(t, obj1, obj2)
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqual(t *testing.T, expected, actual interface{}, msgAndArgs ...interface{}) bool {
t.Helper()
if err := validateEqualArgs(expected, actual); err != nil {
return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
expected, actual, err), msgAndArgs...)
}
if ObjectsAreEqual(expected, actual) {
return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
}
return true
}
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// assert.Empty(t, obj)
func Empty(t *testing.T, object interface{}, msgAndArgs ...interface{}) bool {
pass := isEmpty(object)
if !pass {
t.Helper()
Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
}
return pass
}
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// if assert.NotEmpty(t, obj) {
// assert.Equal(t, "two", obj[1])
// }
func NotEmpty(t *testing.T, object interface{}, msgAndArgs ...interface{}) bool {
pass := !isEmpty(object)
if !pass {
t.Helper()
Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
}
return pass
}
// Nil asserts that the specified object is nil.
//
// assert.Nil(t, err)
func Nil(t *testing.T, object interface{}, msgAndArgs ...interface{}) bool {
if isNil(object) {
return true
}
t.Helper()
return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
}
// NotNil asserts that the specified object is not nil.
//
// assert.NotNil(t, err)
func NotNil(t *testing.T, object interface{}, msgAndArgs ...interface{}) bool {
if !isNil(object) {
return true
}
t.Helper()
return Fail(t, "Expected value not to be nil.", msgAndArgs...)
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// assert.Len(t, mySlice, 3)
func Len(t *testing.T, object interface{}, length int, msgAndArgs ...interface{}) bool {
t.Helper()
ok, l := getLen(object)
if !ok {
return Fail(t, fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...)
}
if l != length {
return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
}
return true
}
// Fail reports a failure through
func Fail(t *testing.T, failureMessage string, msgAndArgs ...interface{}) bool {
t.Helper()
content := []labeledContent{
{"Error", failureMessage},
}
message := messageFromMsgAndArgs(msgAndArgs...)
if len(message) > 0 {
content = append(content, labeledContent{"Messages", message})
}
t.Errorf("\n%s", ""+labeledOutput(content...))
return false
}
// ObjectsAreEqual determines if two objects are considered equal..
func ObjectsAreEqual(expected, actual interface{}) bool {
if expected == nil || actual == nil {
return expected == actual
}
exp, ok := expected.([]byte)
if !ok {
return reflect.DeepEqual(expected, actual)
}
act, ok := actual.([]byte)
if !ok {
return false
}
if exp == nil || act == nil {
return exp == nil && act == nil
}
return bytes.Equal(exp, act)
}
func validateEqualArgs(expected, actual interface{}) error {
if expected == nil && actual == nil {
return nil
}
if isFunction(expected) || isFunction(actual) {
return errors.New("cannot take func type as argument")
}
return nil
}
func formatUnequalValues(expected, actual interface{}) (e string, a string) {
if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)),
fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual))
}
switch expected.(type) {
case time.Duration:
return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual)
}
return truncatingFormat(expected), truncatingFormat(actual)
}
func truncatingFormat(data interface{}) string {
value := fmt.Sprintf("%#v", data)
max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed.
if len(value) > max {
value = value[0:max] + "<... truncated>"
}
return value
}
type labeledContent struct {
label string
content string
}
func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
if len(msgAndArgs) == 0 || msgAndArgs == nil {
return ""
}
if len(msgAndArgs) == 1 {
msg := msgAndArgs[0]
if msgAsStr, ok := msg.(string); ok {
return msgAsStr
}
return fmt.Sprintf("%+v", msg)
}
if len(msgAndArgs) > 1 {
return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
}
return ""
}
func labeledOutput(content ...labeledContent) string {
longestLabel := 0
for _, v := range content {
if len(v.label) > longestLabel {
longestLabel = len(v.label)
}
}
var output string
for _, v := range content {
output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
}
return output
}
func indentMessageLines(message string, longestLabelLen int) string {
outBuf := new(bytes.Buffer)
for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
// no need to align first line because it starts at the correct location (after the label)
if i != 0 {
// append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
}
outBuf.WriteString(scanner.Text())
}
return outBuf.String()
}
func getLen(x interface{}) (ok bool, length int) {
v := reflect.ValueOf(x)
defer func() {
if e := recover(); e != nil {
ok = false
}
}()
return true, v.Len()
}
func isFunction(arg interface{}) bool {
if arg == nil {
return false
}
return reflect.TypeOf(arg).Kind() == reflect.Func
}
func isEmpty(object interface{}) bool {
if object == nil {
return true
}
objValue := reflect.ValueOf(object)
switch objValue.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
return objValue.Len() == 0
case reflect.Ptr:
if objValue.IsNil() {
return true
}
deref := objValue.Elem().Interface()
return isEmpty(deref)
default:
zero := reflect.Zero(objValue.Type())
return reflect.DeepEqual(object, zero.Interface())
}
}
func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool {
for i := 0; i < len(kinds); i++ {
if kind == kinds[i] {
return true
}
}
return false
}
func isNil(object interface{}) bool {
if object == nil {
return true
}
value := reflect.ValueOf(object)
kind := value.Kind()
isNilableKind := containsKind(
[]reflect.Kind{
reflect.Chan, reflect.Func,
reflect.Interface, reflect.Map,
reflect.Ptr, reflect.Slice},
kind)
if isNilableKind && value.IsNil() {
return true
}
return false
}
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package byteutil
import (
"bytes"
"encoding/binary"
"reflect"
"unsafe"
)
// StringToBytes 强制转换 []byte(s)
func StringToBytes(s string) []byte {
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh := reflect.SliceHeader{
Data: sh.Data,
Len: sh.Len,
Cap: sh.Len,
}
return *(*[]byte)(unsafe.Pointer(&bh))
}
// BytesToString 强制转换 string(s)
func BytesToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
// Uint64ToBytes uint64转byte
func Uint64ToBytes(i uint64) []byte {
var buf = make([]byte, 8)
binary.BigEndian.PutUint64(buf, i)
return buf
}
// BytesToUint64 byte转uint64
func BytesToUint64(b []byte) uint64 {
return binary.BigEndian.Uint64(b)
}
// Split 数据分片
func Split(buf []byte, limit int) [][]byte {
var chunk []byte
chunks := make([][]byte, 0, len(buf)/limit+1)
for len(buf) >= limit {
chunk, buf = buf[:limit], buf[limit:]
chunks = append(chunks, chunk)
}
if len(buf) > 0 {
chunks = append(chunks, buf[:])
}
return chunks
}
// Join 数据合并
func Join(s [][]byte) []byte {
return bytes.Join(s, []byte(""))
}
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package byteutil
import (
"bytes"
"testing"
)
func TestStringToBytes(t *testing.T) {
x := "Hello Gopher!"
y := StringToBytes(x)
z := []byte(x)
if !bytes.Equal(y, z) {
t.Fail()
}
}
func TestBytesToString(t *testing.T) {
x := []byte("Hello Gopher!")
y := BytesToString(x)
z := string(x)
if y != z {
t.Fail()
}
}
func TestUint64ToBytes(t *testing.T) {
x := uint64(1234567890)
y := Uint64ToBytes(x)
t.Logf("Uint64ToBytes: %b", y)
}
func TestBytesToUint64(t *testing.T) {
x := uint64(1234567890)
y := Uint64ToBytes(x)
z := BytesToUint64(y)
t.Logf("%d", z)
}
func TestSplit(t *testing.T) {
slice := Split([]byte("Hello Gopher!"), 1)
t.Logf("%s", slice)
}
func TestJoin(t *testing.T) {
b := Join(Split([]byte("Hello Gopher!"), 1))
t.Logf("%s", b)
}
+166
View File
@@ -0,0 +1,166 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package convert
import (
"encoding/base64"
"encoding/json"
"fmt"
"strconv"
"time"
)
// AnyToString ...
func AnyToString(i interface{}) string {
var s string
switch v := i.(type) {
case nil:
s = ""
case int:
s = strconv.Itoa(v)
case int8:
s = strconv.Itoa(int(v))
case int16:
s = strconv.Itoa(int(v))
case int32: // same as `rune`
s = strconv.Itoa(int(v))
case int64:
s = strconv.Itoa(int(v))
case uint:
s = strconv.FormatUint(uint64(v), 10)
case uint8:
s = strconv.FormatUint(uint64(v), 10)
case uint16:
s = strconv.FormatUint(uint64(v), 10)
case uint32:
s = strconv.FormatUint(uint64(v), 10)
case uint64:
s = strconv.FormatUint(v, 10)
case float32:
s = strconv.FormatFloat(float64(v), 'f', -1, 32)
case float64:
s = strconv.FormatFloat(v, 'f', -1, 64)
case bool:
s = strconv.FormatBool(v)
case string:
s = v
case []byte:
s = string(v)
case time.Duration:
s = v.String()
case json.Number:
s = v.String()
default:
s = fmt.Sprint(v)
}
return s
}
// IntToString int => string
func IntToString(i int) string {
return strconv.Itoa(i)
}
// Uint64ToString uint64 => string
func Uint64ToString(i uint64) string {
return strconv.FormatUint(i, 10)
}
// Float64ToString float64 => string
func Float64ToString(f float64) string {
return strconv.FormatFloat(f, 'f', -1, 64)
}
// Float32ToString float32 => string
func Float32ToString(f float32) string {
return strconv.FormatFloat(float64(f), 'f', -1, 32)
}
// StringToFloat64 string => float64
func StringToFloat64(s string) float64 {
f, _ := strconv.ParseFloat(s, 64)
return f
}
// StringToFloat32 string => float32
func StringToFloat32(s string) float32 {
f64, _ := strconv.ParseFloat(s, 32)
return float32(f64)
}
// StringToInt string => int
func StringToInt(s string) int {
i, _ := strconv.Atoi(s)
return i
}
// StringToInt32 string => int32
func StringToInt32(s string) int32 {
return int32(StringToInt64(s))
}
// StringToInt64 string => int64
func StringToInt64(s string) int64 {
i, _ := strconv.ParseInt(s, 10, 64)
return i
}
// StringToUint64 string => uint64
func StringToUint64(s string) uint64 {
i, _ := strconv.ParseUint(s, 10, 64)
return i
}
// IntToUint int => uint
func IntToUint(i int) uint {
return uint(i)
}
// UintToInt uint => int
func UintToInt(i uint) int {
return int(i)
}
// JsonNumberToInt json.Number => int
func JsonNumberToInt(n json.Number) int {
i64, _ := n.Int64()
return int(i64)
}
// MapToJson map => json
func MapToJson(m map[string]string) (string, error) {
b, e := json.Marshal(m)
if e != nil {
return "", e
}
return string(b), nil
}
// JsonToMap json => map
func JsonToMap(s string) (map[string]string, error) {
m := make(map[string]string)
err := json.Unmarshal([]byte(s), &m)
if err != nil {
return nil, err
}
return m, nil
}
// Base64Encode base64 编码
func Base64Encode(src []byte) string {
return base64.StdEncoding.EncodeToString(src)
}
// Base64Decode base64 解码
func Base64Decode(src string) ([]byte, error) {
return base64.StdEncoding.DecodeString(src)
}
+115
View File
@@ -0,0 +1,115 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package csvutil
import (
"bytes"
"encoding/csv"
"io"
"os"
)
// WriteFile 追加写文件
func WriteFile(fileName string, body [][]string, head []string) error {
f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
return err
}
defer f.Close()
w := csv.NewWriter(f)
w.Comma = ','
w.UseCRLF = true
if len(head) > 0 {
r := csv.NewReader(f)
var row []string
if row, err = r.Read(); err != nil || len(row) == 0 {
f.WriteString("\xEF\xBB\xBF")
if err = w.Write(head); err != nil {
return err
}
}
}
err = w.WriteAll(body)
if err != nil {
return err
}
w.Flush()
return nil
}
// WriteBytes 写内存
func WriteBytes(body [][]string, head []string) ([]byte, error) {
var buf bytes.Buffer
w := csv.NewWriter(&buf)
w.Comma = ','
w.UseCRLF = true
if len(head) > 0 {
if buf.Len() == 0 {
buf.WriteString("\xEF\xBB\xBF")
if err := w.Write(head); err != nil {
return nil, err
}
}
}
if err := w.WriteAll(body); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// ReadFile 读文件
func ReadFile(fileName string) ([][]string, []string, error) {
f, err := os.Open(fileName)
if err != nil {
return nil, nil, err
}
defer f.Close()
r := csv.NewReader(f)
content, err := r.ReadAll()
if err != nil {
return nil, nil, err
}
return content[1:], content[0], nil
}
// ReadFileOffset 按行读取文件 offset >= 2
func ReadFileOffset(fileName string, offset, limit int) ([][]string, []string, error) {
f, err := os.Open(fileName)
if err != nil {
return nil, nil, err
}
defer f.Close()
r := csv.NewReader(f)
body := make([][]string, 0)
head := make([]string, 0)
counter := 1
for {
var row []string
if row, err = r.Read(); err != nil && err != io.EOF {
return nil, nil, err
}
if err == io.EOF {
break
}
if counter == 1 {
head = row
} else if counter >= offset && counter < offset+limit {
body = append(body, row)
} else if counter >= offset+limit {
break
}
counter++
}
return body, head, nil
}
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package csvutil
import "testing"
func TestWriteFile(t *testing.T) {
filePath := "testdata.csv"
head := []string{"序号", "姓名", "电话"}
body := make([][]string, 0)
body = append(body, []string{"1", "Mark", "18812345678"}, []string{"2", "马克", "18612345678"})
err := WriteFile(filePath, body, head)
t.Logf("WriteFile: %v", err)
}
func TestWriteBytes(t *testing.T) {
head := []string{"序号", "姓名", "电话"}
body := make([][]string, 0)
body = append(body, []string{"1", "Mark", "18812345678"}, []string{"2", "马克", "18612345678"})
b, _ := WriteBytes(body, head)
t.Logf("WriteBytes: %s", b)
}
func TestReadFile(t *testing.T) {
filePath := "testdata.csv"
body, head, _ := ReadFile(filePath)
t.Logf("body: %s", body)
t.Logf("head: %s", head)
}
func TestReadFileOffset(t *testing.T) {
filePath := "testdata.csv"
body, head, err := ReadFileOffset(filePath, 4, 2)
t.Logf("body: %s", body)
t.Logf("head: %s", head)
t.Logf("err: %v", err)
}
+125
View File
@@ -0,0 +1,125 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package datetime
import "time"
const DefaultLayout string = "2006-01-02 15:04:05"
const DayLayout string = "2006-01-02"
// Time 获取当前时间戳
func Time() int64 {
return time.Now().Unix()
}
// MilliTime 获取当前毫秒时间戳
func MilliTime() int64 {
return time.Now().UnixNano() / 1e6
}
// MicroTime 获取当前微秒时间戳
func MicroTime() int64 {
return time.Now().UnixNano() / 1e3
}
// Date 时间戳格式化
func Date(timestamp int64, layout string) string {
return time.Unix(timestamp, 0).Format(layout)
}
// Timestamp 时间转时间戳
func Timestamp(datetime string, layout string) int64 {
tm2, err := time.ParseInLocation(layout, datetime, time.Local)
if err != nil {
return 0
}
return tm2.Unix()
}
// Datetime 获取当前时间
func Datetime() string {
return Date(Time(), DefaultLayout)
}
// Today 获取今天日期
func Today() string {
return Date(Time(), DayLayout)
}
// TodayStartTime Today => 00:00:00 获取今天起始时间戳
func TodayStartTime() time.Time {
return DayStartTime(time.Now())
}
// TodayEndTime Today => 23:59:59 获取今天结束时间戳
func TodayEndTime() time.Time {
return DayEndTime(time.Now())
}
// DayStartTime Day => 00:00:00 获取当天起始时间戳
func DayStartTime(t time.Time) time.Time {
tm2 := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
return tm2
}
// DayEndTime Day => 23:59:59 获取当天结束时间戳
func DayEndTime(t time.Time) time.Time {
tm2 := time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, time.Local)
return tm2
}
// WeekStartTime Monday => 00:00:00 获取周起始时间戳
func WeekStartTime(t time.Time) time.Time {
offset := int(time.Monday - t.Weekday())
if offset > 0 {
offset = -6
}
tm2 := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local).
AddDate(0, 0, offset)
return tm2
}
//WeekEndTime Sunday => 23:59:59 获取周结束时间戳
func WeekEndTime(t time.Time) time.Time {
offset := 0
if w := t.Weekday(); w != 0 {
offset = int(time.Saturday + 1 - w)
}
tm2 := time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, time.Local).
AddDate(0, 0, offset)
return tm2
}
// MonthStartTime 月初 => 00:00:00 获取月起始时间戳
func MonthStartTime(t time.Time) time.Time {
tm2 := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.Local)
return tm2
}
// MonthEndTime 月末 => 23:59:59 获取月结束时间戳
func MonthEndTime(t time.Time) time.Time {
e := MonthStartTime(t).AddDate(0, 1, -1)
tm2 := time.Date(t.Year(), t.Month(), e.Day(), 23, 59, 59, 0, time.Local)
return tm2
}
// YearStartTime 年初 => 00:00:00 获取年起始时间戳
func YearStartTime(t time.Time) time.Time {
tm2 := time.Date(t.Year(), time.January, 1, 0, 0, 0, 0, time.Local)
return tm2
}
// YearEndTime 年末 => 23:59:59 获取年起始时间戳
func YearEndTime(t time.Time) time.Time {
tm2 := time.Date(t.Year(), time.December, 31, 23, 59, 59, 0, time.Local)
return tm2
}
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package datetime
import (
"testing"
"time"
)
func TestTime(t *testing.T) {
t.Logf("Time: %d", Time())
}
func TestMilliTime(t *testing.T) {
t.Logf("MilliTime: %d", MilliTime())
}
func TestMicroTime(t *testing.T) {
t.Logf("MicroTime: %d", MicroTime())
}
func TestDateTime(t *testing.T) {
t.Logf("Datetime: %s", Datetime())
}
func TestTimestamp(t *testing.T) {
datetime := "2021-06-06 11:11:11"
t.Logf("Date: %d", Timestamp(datetime, DefaultLayout))
}
func TestToday(t *testing.T) {
t.Logf("Today: %s", Today())
}
func TestTodayStartTime(t *testing.T) {
t.Logf("TodayStartTime: %v", TodayStartTime())
}
func TestTodayEndTime(t *testing.T) {
t.Logf("TodayEndTime: %v", TodayEndTime())
}
func TestDayStartTime(t *testing.T) {
t.Logf("DayStartTime: %v", DayStartTime(time.Now()))
}
func TestDayEndTime(t *testing.T) {
t.Logf("DayEndTime: %v", DayEndTime(time.Now()))
}
func TestWeekStartTime(t *testing.T) {
t.Logf("WeekStartTime: %v", WeekStartTime(time.Now()))
}
func TestWeekEndTime(t *testing.T) {
t.Logf("WeekEndTime: %v", WeekEndTime(time.Now()))
}
func TestMonthStartTime(t *testing.T) {
t.Logf("MonthStartTime: %v", MonthStartTime(time.Now()))
}
func TestMonthEndTime(t *testing.T) {
t.Logf("MonthEndTime: %v", MonthEndTime(time.Now()))
}
func TestYearStartTime(t *testing.T) {
t.Logf("YearStartTime: %v", YearStartTime(time.Now()))
}
func TestYearEndTime(t *testing.T) {
t.Logf("YearEndTime: %v", YearEndTime(time.Now()))
}
+119
View File
@@ -0,0 +1,119 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package fileutil
import (
"errors"
"io/ioutil"
"os"
"path"
"path/filepath"
)
// SelfPath gets compiled executable file absolute path.
func SelfPath() string {
selfPath, _ := filepath.Abs(os.Args[0])
return selfPath
}
// SelfDir gets compiled executable file directory.
func SelfDir() string {
return filepath.Dir(SelfPath())
}
//MkDir 创建目录.
func MkDir(dirPath string) error {
if IsExist(dirPath) {
return nil
}
return os.MkdirAll(dirPath, os.ModePerm)
}
// IsExist 判断文件或目录是否存在.
func IsExist(filePath string) bool {
_, err := os.Stat(filePath)
return err == nil || os.IsExist(err)
}
// IsEmpty 判断目录是否为空.
func IsEmpty(dirname string) bool {
dir, _ := ioutil.ReadDir(dirname)
if len(dir) == 0 {
return true
} else {
return false
}
}
// IsFile 判断文件是否存在.
func IsFile(filePath string) bool {
f, e := os.Stat(filePath)
if e != nil {
return false
}
return !f.IsDir()
}
// IsDir 判断目录是否存在.
func IsDir(filePath string) bool {
f, e := os.Stat(filePath)
if e != nil {
return false
}
return f.IsDir()
}
// ListIndex 目录下文件和子目录列表.
func ListIndex(dirPath string) ([]string, []string, error) {
if !IsDir(dirPath) {
return nil, nil, errors.New(dirPath + " not a directory")
}
fs, err := ioutil.ReadDir(dirPath)
var files, dirs []string
for _, fi := range fs {
if !fi.IsDir() {
files = append(files, fi.Name())
} else {
dirs = append(dirs, fi.Name())
}
}
return files, dirs, err
}
// ClearDir 清空目录下所有文件不包括子目录.
func ClearDir(dirPath string) error {
dir, e := ioutil.ReadDir(dirPath)
for _, d := range dir {
if d.IsDir() {
continue
}
_ = os.Remove(path.Join([]string{dirPath, d.Name()}...))
}
return e
}
// ClearDirF 清空目录下所有文件和目录.
func ClearDirF(dirPath string) error {
dir, e := ioutil.ReadDir(dirPath)
for _, d := range dir {
_ = os.RemoveAll(path.Join([]string{dirPath, d.Name()}...))
}
return e
}
// RemoveDir 删除空目录.
func RemoveDir(dirPath string) error {
if !IsDir(dirPath) {
return errors.New(dirPath + " not a directory")
}
return os.Remove(dirPath)
}
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package fileutil
import (
"testing"
)
func TestSelfPath(t *testing.T) {
t.Logf("SelfPath: %v", SelfPath())
}
func TestSelfDir(t *testing.T) {
t.Logf("SelfDir: %v", SelfDir())
}
func TestMkDir(t *testing.T) {
dirPath := "testdata/dir/dir1"
t.Logf("Mkdir: %v", MkDir(dirPath))
}
func TestIsEmpty(t *testing.T) {
dirPath := "testdata/dir"
t.Logf("IsEmpty: %v", IsEmpty(dirPath))
}
func TestIsDir(t *testing.T) {
dirPath := "testdata/dir"
t.Logf("IsDir: %v", IsDir(dirPath))
}
func TestIsFile(t *testing.T) {
dirPath := "testdata/dir"
t.Logf("IsFile: %v", IsFile(dirPath))
}
func TestListIndex(t *testing.T) {
dirPath := "testdata"
files, dirs, err := ListIndex(dirPath)
t.Logf("ListFiles: %v, %v, %v", files, dirs, err)
}
func TestClearDir(t *testing.T) {
dirPath := "testdata/dir/dir1"
t.Logf("ClearDir: %v", ClearDir(dirPath))
}
func TestClearDirF(t *testing.T) {
dirPath := "testdata"
t.Logf("ClearDirF: %v", ClearDirF(dirPath))
}
func TestRemoveDir(t *testing.T) {
dirPath := "testdata"
t.Logf("RemoveDir: %v", RemoveDir(dirPath))
}
+98
View File
@@ -0,0 +1,98 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package fileutil
import (
"bufio"
"bytes"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
)
/**
os.O_WRONLY 只写
os.O_CREATE 创建文件
os.O_RDONLY 只读
os.O_RDWR 读写
os.O_TRUNC 清空
os.O_APPEND 追加
*/
// CreateFile 创建或清空文件
func CreateFile(filePath string) (*os.File, error) {
if err := MkDir(path.Dir(filePath)); err != nil {
return nil, err
}
return os.Create(filePath)
}
// ReadFileToBytes 读文件
func ReadFileToBytes(filePath string) ([]byte, error) {
b, err := ioutil.ReadFile(filePath)
if err != nil {
return nil, err
}
return b, nil
}
// WriteBytesToFile 写文件 覆盖
func WriteBytesToFile(filePath string, b []byte) error {
f, err := CreateFile(filePath)
if err != nil {
return err
}
defer f.Close()
wt := bufio.NewWriter(f)
_, err = io.Copy(wt, bytes.NewReader(b))
if err != nil {
return err
}
wt.Flush()
return nil
}
// ReadHttpFileToBytes 读网络文件
func ReadHttpFileToBytes(fileUrl string) ([]byte, error) {
resp, err := http.Get(fileUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}
// Copy 复制文件
func Copy(sourcePath, targetPath string) error {
b, err := ReadFileToBytes(sourcePath)
if err != nil {
return nil
}
return WriteBytesToFile(targetPath, b)
}
// Download 下载文件
func Download(sourceUrl, targetPath string) error {
b, err := ReadHttpFileToBytes(sourceUrl)
if err != nil {
return nil
}
return WriteBytesToFile(targetPath, b)
}
// Name 获取文件名.
func Name(filePath string) string {
return filepath.Base(filePath)
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package fileutil
import (
"testing"
)
func TestCreateFile(t *testing.T) {
filePath := "testdata/file/create.txt"
fs, err := CreateFile(filePath)
defer fs.Close()
t.Logf("CreateFile: %v", err)
}
func TestWriteBytesToFile(t *testing.T) {
filePath := "testdata/file/write.txt"
t.Logf("WriteBytesToFile: %v", WriteBytesToFile(filePath, []byte("hello")))
}
func TestReadFileToBytes(t *testing.T) {
filePath := "testdata/file/write.txt"
b, err := ReadFileToBytes(filePath)
t.Logf("ReadFileToBytes: %v, %v", string(b), err)
}
func TestReadHttpFileToBytes(t *testing.T) {
filePath := "https://game.gtimg.cn/images/yxzj/img201606/heroimg/109/109.jpg"
b, err := ReadHttpFileToBytes(filePath)
err = WriteBytesToFile("testdata/file/httpFile.jpeg", b)
t.Logf("ReadHttpFileToBytes: %v", err)
}
func TestCopy(t *testing.T) {
sourcePath := "testdata/file/write.txt"
targetPath := "testdata/file/target.txt"
t.Logf("Copy: %v", Copy(sourcePath, targetPath))
}
func TestDownload(t *testing.T) {
sourceUrl := "https://game.gtimg.cn/images/yxzj/img201606/heroimg/109/109.jpg"
targetPath := "testdata/file/109-download.jpeg"
t.Logf("Copy: %v", Download(sourceUrl, targetPath))
}
func TestName(t *testing.T) {
t.Logf("Name: %v", Name("testdata/file/109-download.jpeg"))
}
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package hashutil
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"hash"
)
// Md5 hashes using md5 algorithm
func Md5(b []byte) []byte {
return Hashes(md5.New(), b)
}
// Md5Hex hashes using md5 algorithm
func Md5Hex(text string) string {
return StringHashes(md5.New(), text)
}
// Sha1 hashes using sha1 algorithm
func Sha1(b []byte) []byte {
return Hashes(sha1.New(), b)
}
// Sha1Hex hashes using sha1 algorithm
func Sha1Hex(text string) string {
return StringHashes(sha1.New(), text)
}
// Sha256 hashes using sha256 algorithm
func Sha256(b []byte) []byte {
return Hashes(sha256.New(), b)
}
// Sha256Hex hashes using sha256 algorithm
func Sha256Hex(text string) string {
return StringHashes(sha256.New(), text)
}
// Sha512 hashes using sha512 algorithm
func Sha512(b []byte) []byte {
return Hashes(sha512.New(), b)
}
// Sha512Hex hashes using sha512 algorithm
func Sha512Hex(text string) string {
return StringHashes(sha512.New(), text)
}
// HmacMd5 hashes using md5 algorithm with a secret
func HmacMd5(b []byte, secret []byte) []byte {
algorithm := hmac.New(md5.New, secret)
return Hashes(algorithm, b)
}
// HmacMd5Hex hashes using md5 algorithm with a secret
func HmacMd5Hex(text, secret string) string {
return StringHashes(hmac.New(md5.New, []byte(secret)), text)
}
// HmacSha256 hashes using sha256 algorithm with a secret
func HmacSha256(b []byte, secret []byte) []byte {
return Hashes(hmac.New(sha256.New, secret), b)
}
// HmacSha256Hex hashes using sha256 algorithm with a secret
func HmacSha256Hex(text, secret string) string {
return StringHashes(hmac.New(sha256.New, []byte(secret)), text)
}
// HmacSha512 hashes using sha512 algorithm with a secret
func HmacSha512(b []byte, secret []byte) []byte {
return Hashes(hmac.New(sha512.New, secret), b)
}
// HmacSha512Hex hashes using sha512 algorithm with a secret
func HmacSha512Hex(text, secret string) string {
return StringHashes(hmac.New(sha512.New, []byte(secret)), text)
}
// StringHashes hashes string
func StringHashes(algorithm hash.Hash, text string) string {
return hex.EncodeToString(Hashes(algorithm, []byte(text)))
}
// Hashes hashes
func Hashes(algorithm hash.Hash, b []byte) []byte {
algorithm.Write(b)
return algorithm.Sum(nil)
}
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package httputil
import (
"io/ioutil"
"net/http"
"strings"
)
func PostWithHeader(url string, msg []byte, headers map[string]string) (string, error) {
client := &http.Client{}
req, err := http.NewRequest("POST", url, strings.NewReader(string(msg)))
if err != nil {
return "", err
}
for key, header := range headers {
req.Header.Set(key, header)
}
resp, err := client.Do(req)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}
func PostWithAuthorization(url, authorization string, msg []byte) (string, error) {
headers := make(map[string]string)
headers["Authorization"] = authorization
headers["Content-Type"] = "application/json"
return PostWithHeader(url, msg, headers)
}
+81
View File
@@ -0,0 +1,81 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package maputil
import "strings"
// IsEmpty ...
func IsEmpty(mp map[string]string) bool {
return len(mp) == 0
}
// HasKey ...
func HasKey(mp map[string]string, key string) bool {
if _, ok := mp[key]; ok {
return true
}
return false
}
// Value ...
func Value(mp map[string]string, key string) string {
if HasKey(mp, key) {
return mp[key]
}
return ""
}
// HasValue ...
func HasValue(mp map[string]string, value string) bool {
for _, v := range mp {
if v == value {
return true
}
}
return false
}
// Keys ...
func Keys(mp map[string]string) []string {
ks := make([]string, 0, len(mp))
for k, _ := range mp {
ks = append(ks, k)
}
return ks
}
// Values ...
func Values(mp map[string]string) []string {
vs := make([]string, 0, len(mp))
for _, v := range mp {
vs = append(vs, v)
}
return vs
}
// KeyToLower convert keys to lower case.
func KeyToLower(mp map[string]string) map[string]string {
nmp := make(map[string]string, len(mp))
for k, v := range mp {
k = strings.ToLower(k)
nmp[k] = v
}
return nmp
}
// Merge src 会覆盖 dst
func Merge(src, dst map[string]string) map[string]string {
for k, v := range src {
dst[k] = v
}
return dst
}
+106
View File
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package mask
import (
"strings"
)
// Mask 自定义字符脱敏 保留前f位和最后e位
func Mask(s string, f, e int) string {
l := len(s)
if f+e >= l || f < 0 || e < 0 {
return ""
}
return s[0:f] + strings.Repeat("*", l-f-e) + s[l-e:]
}
// Left 保留前f位
func Left(s string, f int) string {
return Mask(s, f, 0)
}
// Right 保留后e位
func Right(s string, e int) string {
return Mask(s, 0, e)
}
// First 取值前f位
func First(s string, f int) string {
l := len(s)
if l <= f || f < 0 {
return s
}
return s[0:f]
}
// Last 取值后e位
func Last(s string, e int) string {
l := len(s)
if l <= e || e < 0 {
return s
}
return s[l-e:]
}
// LastFour 后四位
func LastFour(s string) string {
return Last(s, 4)
}
// IdCard 身份证号脱敏
func IdCard(s string) string {
if len(s) != 18 {
return ""
}
return s[0:4] + " **** **** " + s[len(s)-4:]
}
// IdCardStrict 严格身份证号脱敏
func IdCardStrict(s string) string {
if len(s) != 18 {
return ""
}
return s[0:1] + "*** **** **** ***" + s[len(s)-1:]
}
// Mobile 手机号脱敏
func Mobile(s string) string {
return s[0:3] + "****" + s[len(s)-4:]
}
// ChineseName 中文姓名脱敏
func ChineseName(s string) string {
r := []rune(s)
l := len(r)
if l == 2 {
return "*" + string(r[1:])
} else if l == 3 {
return "*" + string(r[l-2:])
} else if l == 4 {
return "**" + string(r[l-2:])
} else if l > 4 {
return string(r[:1]) + strings.Repeat("*", l-3) + string(r[l-2:])
}
return "**"
}
// Email 邮箱脱敏
func Email(s string) string {
ss := strings.Split(s, "@")
l := len(ss[0])
if l <= 1 {
return "*@" + ss[1]
}
r := []rune(s)
return string(r[0:1]) + strings.Repeat("*", l-1) + "@" + ss[1]
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package mathutil
// MaxInt64 ...
func MaxInt64(is ...int64) int64 {
max := is[0]
for _, v := range is {
if v > max {
max = v
}
}
return max
}
// MinInt64 ...
func MinInt64(is ...int64) int64 {
min := is[0]
for _, v := range is {
if v < min {
min = v
}
}
return min
}
+67
View File
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package random
import (
"bytes"
"math/rand"
"sync"
"time"
)
var (
randSeek = int64(1)
l sync.Mutex
)
// GetRandomInt 生成值小于max的随机数
func GetRandomInt(max int) int {
rand.Seed(getRandSeek())
return rand.Intn(max)
}
// GetRandomChars 生成英文字母随机字符串
func GetRandomChars(num int) string {
ss := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
return GetRandomString(num, ss)
}
// GetRandomNumbers 生成数字类型随机字符串
func GetRandomNumbers(num int) string {
return GetRandomString(num)
}
// GetRandomString 生成随机字符串
func GetRandomString(num int, str ...string) string {
s := "0123456789"
if len(str) > 0 {
s = str[0]
}
l := len(s)
r := rand.New(rand.NewSource(getRandSeek()))
var buf bytes.Buffer
for i := 0; i < num; i++ {
x := r.Intn(l)
buf.WriteString(s[x : x+1])
}
return buf.String()
}
func getRandSeek() int64 {
l.Lock()
if randSeek >= 100000000 {
randSeek = 1
}
randSeek++
l.Unlock()
return time.Now().UnixNano() + randSeek
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package random
import (
"testing"
)
func TestGetRandomSring(t *testing.T) {
t.Logf("GetRandomString: %s", GetRandomString(4, "abide123456"))
t.Logf("GetRandomString: %s", GetRandomString(6, "abcdefghijklmnopqrstuvwxyz0123456789"))
}
func TestGetRandomChars(t *testing.T) {
t.Logf("GetRandomChars: %s", GetRandomChars(4))
t.Logf("GetRandomChars: %s", GetRandomChars(6))
}
func TestGetRandomNumbers(t *testing.T) {
t.Logf("GetRandomNumbers: %s", GetRandomNumbers(4))
t.Logf("GetRandomNumbers: %s", GetRandomNumbers(6))
}
func TestGetRandomInt(t *testing.T) {
t.Logf("GetRandomInt: %d", GetRandomInt(10))
t.Logf("GetRandomInt: %d", GetRandomInt(10000))
}
+133
View File
@@ -0,0 +1,133 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package rsautil
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/hex"
)
// EncryptToBase64 ...
func EncryptToBase64(plainText []byte, base64PubKey string) (string, error) {
publicBytes, err := base64.StdEncoding.DecodeString(base64PubKey)
if err != nil {
return "", err
}
cipherBytes, err := encrypt(plainText, publicBytes)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(cipherBytes), nil
}
// DecryptByBase64 ...
func DecryptByBase64(cipherText, base64PriKey string) ([]byte, error) {
privateBytes, err := base64.StdEncoding.DecodeString(base64PriKey)
if err != nil {
return nil, err
}
cipherBytes, err := base64.StdEncoding.DecodeString(cipherText)
if err != nil {
return nil, err
}
return decrypt(cipherBytes, privateBytes)
}
// EncryptToHex ...
func EncryptToHex(plainText []byte, hexPubKey string) (string, error) {
publicBytes, err := hex.DecodeString(hexPubKey)
if err != nil {
return "", err
}
cipherBytes, err := encrypt(plainText, publicBytes)
if err != nil {
return "", err
}
return hex.EncodeToString(cipherBytes), nil
}
// DecryptByHex ...
func DecryptByHex(cipherText, hexPriKey string) ([]byte, error) {
privateBytes, err := hex.DecodeString(hexPriKey)
if err != nil {
return nil, err
}
cipherTextBytes, err := hex.DecodeString(cipherText)
if err != nil {
return nil, err
}
return decrypt(cipherTextBytes, privateBytes)
}
// encrypt 加密
func encrypt(plainText, pubKey []byte) ([]byte, error) {
pub, err := x509.ParsePKIXPublicKey(pubKey)
if err != nil {
return nil, err
}
publicKey := pub.(*rsa.PublicKey)
pubSize, plainTextSize := publicKey.Size(), len(plainText)
// EncryptPKCS1v15 encrypts the given message with RSA and the padding
// scheme from PKCS #1 v1.5. The message must be no longer than the
// length of the public modulus minus 11 bytes.
//
// The rand parameter is used as a source of entropy to ensure that
// encrypting the same message twice doesn't result in the same
// ciphertext.
//
// WARNING: use of this function to encrypt plaintexts other than
// session keys is dangerous. Use RSA OAEP in new protocols.
offSet, once := 0, pubSize-11
buffer := bytes.Buffer{}
for offSet < plainTextSize {
endIndex := offSet + once
if endIndex > plainTextSize {
endIndex = plainTextSize
}
bytesOnce, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText[offSet:endIndex])
if err != nil {
return nil, err
}
buffer.Write(bytesOnce)
offSet = endIndex
}
return buffer.Bytes(), nil
}
// decrypt 解密
func decrypt(cipherText, priKey []byte) (plainText []byte, err error) {
pri, err := x509.ParsePKCS8PrivateKey(priKey)
if err != nil {
return []byte{}, err
}
privateKey := pri.(*rsa.PrivateKey)
priSize, cipherTextSize := privateKey.Size(), len(cipherText)
var offSet = 0
var buffer = bytes.Buffer{}
for offSet < cipherTextSize {
endIndex := offSet + priSize
if endIndex > cipherTextSize {
endIndex = cipherTextSize
}
bytesOnce, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherText[offSet:endIndex])
if err != nil {
return nil, err
}
buffer.Write(bytesOnce)
offSet = endIndex
}
return buffer.Bytes(), nil
}
+76
View File
@@ -0,0 +1,76 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package rsautil
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"errors"
)
var (
RSABitsErr = errors.New("bits 1024 or 2048")
RSAPrivateKeyPemDecodeErr = errors.New("private key pem.decode error")
RSAPublicKeyPemDecodeErr = errors.New("public key pem.decode error")
)
type RsaKey struct {
PrivateKey string // PKCS#8
PublicKey string // PKCS#8
}
// GenerateRsaKey 生成公钥私钥
func GenerateRsaKey(bits int) ([]byte, []byte, error) {
if bits != 1024 && bits != 2048 {
return nil, nil, RSABitsErr
}
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, nil, err
}
priKey, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, nil, err
}
pubKey, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
if err != nil {
return nil, nil, err
}
return priKey, pubKey, nil
}
// GenerateRsaKeyBase64 生成公钥私钥 Base64
func GenerateRsaKeyBase64(bits int) (RsaKey, error) {
priKey, pubKey, err := GenerateRsaKey(bits)
if err != nil {
return RsaKey{}, err
}
return RsaKey{
PrivateKey: base64.StdEncoding.EncodeToString(priKey),
PublicKey: base64.StdEncoding.EncodeToString(pubKey),
}, nil
}
// GenerateRsaKeyHex 生成公钥私钥 Hex
func GenerateRsaKeyHex(bits int) (RsaKey, error) {
priKey, pubKey, err := GenerateRsaKey(bits)
if err != nil {
return RsaKey{}, err
}
return RsaKey{
PrivateKey: hex.EncodeToString(priKey),
PublicKey: hex.EncodeToString(pubKey),
}, nil
}
+220
View File
@@ -0,0 +1,220 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package sliceutil
import (
"strings"
)
// InSlice 判断字符串是否存在
func InSlice(value string, ss []string) bool {
for _, v := range ss {
if v == value {
return true
}
}
return false
}
// IsEmpty 判断Slice是否为空
func IsEmpty(ss []string) bool {
if len(ss) == 0 {
return true
}
return false
}
// Implode 别名 strings.Join
func Implode(sep string, ss ...string) string {
return strings.Join(ss, sep)
}
// Explode 别名 strings.Split
func Explode(sep string, s string) []string {
return strings.Split(s, sep)
}
// Unique slice去重
func Unique(ss []string) []string {
l := len(ss)
// 无法保障顺序
m := make(map[string]bool)
for i := 0; i < l; i++ {
m[ss[i]] = true
}
nl := len(m)
n := make([]string, nl)
i := 0
for v := range m {
n[i] = v
i++
}
return n
}
// Merge slice合并 - 不去重
func Merge(slice1, slice2 []string) []string {
n := make([]string, len(slice1)+len(slice2))
copy(n, slice1)
copy(n[len(slice1):], slice2)
return n
}
// Intersect slice交集
func Intersect(slice1, slice2 []string) []string {
m := make(map[string]int)
n := make([]string, 0)
for _, v := range slice1 {
m[v]++
}
for _, v := range slice2 {
times, _ := m[v]
if times == 1 {
n = append(n, v)
}
}
return n
}
// Union slice并集
func Union(slice1, slice2 []string) []string {
m := make(map[string]int)
for _, v := range slice1 {
m[v]++
}
for _, v := range slice2 {
times, _ := m[v]
if times == 0 {
slice1 = append(slice1, v)
}
}
return slice1
}
// Difference slice差集 - 属于slice1,不属于slice2
func Difference(slice1, slice2 []string) []string {
m := make(map[string]int)
n := make([]string, 0)
inter := Intersect(slice1, slice2)
for _, v := range inter {
m[v]++
}
for _, value := range slice1 {
times, _ := m[value]
if times == 0 {
n = append(n, value)
}
}
return n
}
// IntersectUint64 slice交集
func IntersectUint64(slice1, slice2 []uint64) []uint64 {
m := make(map[uint64]int)
n := make([]uint64, 0)
for _, v := range slice1 {
m[v]++
}
for _, v := range slice2 {
times, _ := m[v]
if times == 1 {
n = append(n, v)
}
}
return n
}
// UnionUint64 slice并集
func UnionUint64(slice1, slice2 []uint64) []uint64 {
m := make(map[uint64]int)
for _, v := range slice1 {
m[v]++
}
for _, v := range slice2 {
times, _ := m[v]
if times == 0 {
slice1 = append(slice1, v)
}
}
return slice1
}
// DifferenceUint64 slice差集 - 属于slice1,不属于slice2
func DifferenceUint64(slice1, slice2 []uint64) []uint64 {
m := make(map[uint64]int)
n := make([]uint64, 0)
inter := IntersectUint64(slice1, slice2)
for _, v := range inter {
m[v]++
}
for _, value := range slice1 {
times, _ := m[value]
if times == 0 {
n = append(n, value)
}
}
return n
}
// IntersectInterface slice交集
func IntersectInterface(slice1, slice2 []interface{}) []interface{} {
m := make(map[interface{}]int)
n := make([]interface{}, 0)
for _, v := range slice1 {
m[v]++
}
for _, v := range slice2 {
times, _ := m[v]
if times == 1 {
n = append(n, v)
}
}
return n
}
// UnionInterface slice并集
func UnionInterface(slice1, slice2 []interface{}) []interface{} {
m := make(map[interface{}]int)
for _, v := range slice1 {
m[v]++
}
for _, v := range slice2 {
times, _ := m[v]
if times == 0 {
slice1 = append(slice1, v)
}
}
return slice1
}
// DifferenceInterface slice差集 - 属于slice1,不属于slice2
func DifferenceInterface(slice1, slice2 []interface{}) []interface{} {
m := make(map[interface{}]int)
n := make([]interface{}, 0)
inter := IntersectInterface(slice1, slice2)
for _, v := range inter {
m[v]++
}
for _, value := range slice1 {
times, _ := m[value]
if times == 0 {
n = append(n, value)
}
}
return n
}
+127
View File
@@ -0,0 +1,127 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package stringutil
import (
"bytes"
"net/url"
"regexp"
"strings"
"unicode"
)
// Reverse 反转字符串
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
// UcFirst 首字母大写
func UcFirst(s string) string {
for i, v := range s {
return string(unicode.ToUpper(v)) + s[i+1:]
}
return s
}
// LcFirst 首字母小写
func LcFirst(s string) string {
for i, v := range s {
return string(unicode.ToLower(v)) + s[i+1:]
}
return s
}
// CamelToSnake camel => snake 简单实现
func CamelToSnake(s string) string {
buffer := new(bytes.Buffer)
for i, r := range s {
if unicode.IsUpper(r) {
if i != 0 {
buffer.WriteRune('_')
}
buffer.WriteRune(unicode.ToLower(r))
} else {
buffer.WriteRune(r)
}
}
return buffer.String()
}
// SnakeToCamel snake => camel 简单实现
func SnakeToCamel(s string) string {
s = strings.Replace(s, "_", " ", -1)
s = strings.Title(s)
return strings.Replace(s, " ", "", -1)
}
func SnakeToSpinal(s string) string {
return strings.Replace(s, "_", "-", -1)
}
func SpinalToSnake(s string) string {
return strings.Replace(s, "-", "_", -1)
}
// UrlEncode 空格被编码为+,+被编码为%2B
func UrlEncode(s string) string {
return url.QueryEscape(s)
}
// UrlDecode URL解码
func UrlDecode(s string) string {
u, _ := url.QueryUnescape(s)
return u
}
// Substr 字符串切割
func Substr(s string, pos, length int) string {
r := []rune(s)
sl := len(r)
if pos >= sl {
return ""
}
idx := pos + length
if length == 0 || idx > sl {
idx = sl
} else if length < 0 {
idx = sl + length
}
return string(r[pos:idx])
}
// InString 判断子字符串是否存在
func InString(sub, str string) bool {
if str != "" && strings.Contains(str, sub) {
return true
}
return false
}
// RegexpReplace ...
func RegexpReplace(src, expr, repl string) (string, error) {
reg, err := regexp.Compile(expr)
return reg.ReplaceAllString(src, repl), err
}
// TrimSpace 去除字符串前后空格、换行等
func TrimSpace(s string) string {
s = strings.TrimSpace(s)
s = strings.Trim(s, "\r")
s = strings.Trim(s, "\n")
s = strings.Trim(s, "\t")
return s
}