package strutil

import (
	
	
	
	
	
	

	
)

// Equal check, alias of strings.EqualFold
var Equal = strings.EqualFold
var IsHttpURL = checkfn.IsHttpURL

// IsNumChar returns true if the given character is a numeric, otherwise false.
func ( byte) bool { return  >= '0' &&  <= '9' }

var (
	uintReg = regexp.MustCompile(`^\d+$`)
	intReg  = regexp.MustCompile(`^[-+]?\d+$`)

	floatReg = regexp.MustCompile(`^[-+]?\d*\.?\d+$`)
)

// IsInt check the string is an integer number
func ( string) bool {
	if  == "" {
		return false
	}
	return intReg.MatchString()
}

// IsUint check the string is an unsigned integer number
func ( string) bool {
	if  == "" {
		return false
	}
	return uintReg.MatchString()
}

// IsFloat check the string is a float number
func ( string) bool {
	if  == "" {
		return false
	}
	return floatReg.MatchString()
}

// IsNumeric returns true if the given string is a numeric(int/float), otherwise false.
func ( string) bool { return checkfn.IsNumeric() }

// IsPositiveNum check the string is a positive number
func ( string) bool { return checkfn.IsPositiveNum() }

// IsAlphabet char
func ( uint8) bool {
	// A 65 -> Z 90
	if  >= 'A' &&  <= 'Z' {
		return true
	}

	// a 97 -> z 122
	if  >= 'a' &&  <= 'z' {
		return true
	}
	return false
}

// IsAlphaNum reports whether the byte is an ASCII letter, number, or underscore
func ( uint8) bool {
	return  == '_' || '0' <=  &&  <= '9' || 'a' <=  &&  <= 'z' || 'A' <=  &&  <= 'Z'
}

// IsUpper returns true if the given string is an uppercase, otherwise false.
func ( string) bool {
	for  := 0;  < len(); ++ {
		if [] >= 'A' && [] <= 'Z' {
			continue
		}
		return false
	}
	return true
}

// IsLower returns true if the given string is a lowercase, otherwise false.
func ( string) bool {
	for  := 0;  < len(); ++ {
		if [] >= 'a' && [] <= 'z' {
			continue
		}
		return false
	}
	return true
}

// IsAllASCII 判断字符串是否全为可打印 ASCII(无中文等多字节字符)
func ( string) bool {
	for  := 0;  < len(); ++ {
		if [] > 0x7E || [] < 0x20 {
			return false
		}
	}
	return true
}

// StrPos alias of the strings.Index
func (,  string) int { return strings.Index(, ) }

// BytePos alias of the strings.IndexByte
func ( string,  byte) int { return strings.IndexByte(, ) }

// IEqual ignore case check given two strings are equals.
func (,  string) bool { return strings.EqualFold(, ) }

// NoCaseEq check two strings is equals and case-insensitivity
func (,  string) bool { return strings.EqualFold(, ) }

// IContains ignore case check substr in the given string.
func (,  string) bool {
	return strings.Contains(strings.ToLower(), strings.ToLower())
}

// ContainsByte in given string.
func ( string,  byte) bool { return strings.IndexByte(, ) >= 0 }

// ContainsByteOne in given string.
func ( string,  []byte) bool {
	for ,  := range  {
		if strings.IndexByte(, ) >= 0 {
			return true
		}
	}
	return false
}

// InArray alias of HasOneSub()
var InArray = HasOneSub

// ContainsOne substr(s) in the given string. alias of HasOneSub()
func ( string,  []string) bool { return HasOneSub(, ) }

// HasOneSub substr(s) in the given string.
func ( string,  []string) bool {
	for ,  := range  {
		if strings.Contains(, ) {
			return true
		}
	}
	return false
}

// IContainsOne ignore case check has one substr(s) in the given string.
func ( string,  []string) bool {
	 = strings.ToLower()
	for ,  := range  {
		if strings.Contains(, strings.ToLower()) {
			return true
		}
	}
	return false
}

// ContainsAll given string should contain all substrings. alias of HasAllSubs()
func ( string,  []string) bool { return HasAllSubs(, ) }

// HasAllSubs given string should contain all substrings
func ( string,  []string) bool {
	for ,  := range  {
		if !strings.Contains(, ) {
			return false
		}
	}
	return true
}

// IContainsAll like ContainsAll(), but ignore case
func ( string,  []string) bool {
	 = strings.ToLower()
	for ,  := range  {
		if !strings.Contains(, strings.ToLower()) {
			return false
		}
	}
	return true
}

// StartsWithAny alias of the HasOnePrefix
var StartsWithAny = HasOneSuffix

// IsStartsOf alias of the HasOnePrefix
func ( string,  []string) bool {
	return HasOnePrefix(, )
}

// HasOnePrefix the string starts with one of the subs
func ( string,  []string) bool {
	for ,  := range  {
		if len() >= len() && [0:len()] ==  {
			return true
		}
	}
	return false
}

// StartsWith alias func for HasPrefix
var StartsWith = strings.HasPrefix

// HasPrefix substr in the given string.
func ( string,  string) bool { return strings.HasPrefix(, ) }

// IsStartOf alias of the strings.HasPrefix
func (,  string) bool { return strings.HasPrefix(, ) }

// HasSuffix substr in the given string.
func ( string,  string) bool { return strings.HasSuffix(, ) }

// IsEndOf alias of the strings.HasSuffix
func (,  string) bool { return strings.HasSuffix(, ) }

// HasOneSuffix the string end with one of the subs
func ( string,  []string) bool {
	for ,  := range  {
		if strings.HasSuffix(, ) {
			return true
		}
	}
	return false
}

// IsValidUtf8 valid utf8 string check
func ( string) bool { return utf8.ValidString() }

// ----- refer from github.com/yuin/goldmark/util

// refer from github.com/yuin/goldmark/util
var spaceTable = [256]int8{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}

// IsSpace returns true if the given character is a space, otherwise false.
func ( byte) bool { return spaceTable[] == 1 }

// IsEmpty returns true if the given string is empty.
func ( string) bool { return len() == 0 }

// IsBlank returns true if the given string is all space characters.
func ( string) bool { return IsBlankBytes([]byte()) }

// IsNotBlank returns true if the given string is not blank.
func ( string) bool { return !IsBlankBytes([]byte()) }

// IsBlankBytes returns true if the given []byte is all space characters.
func ( []byte) bool {
	for ,  := range  {
		if !IsSpace() {
			return false
		}
	}
	return true
}

// IsSymbol reports whether the rune is a symbolic character.
func ( rune) bool { return unicode.IsSymbol() }

// HasEmpty value for input strings
func ( ...string) bool {
	for ,  := range  {
		if  == "" {
			return true
		}
	}
	return false
}

// IsAllEmpty for input strings
func ( ...string) bool {
	for ,  := range  {
		if  != "" {
			return false
		}
	}
	return true
}

var (
	// regex for check version number
	verRegex = regexp.MustCompile(`^[0-9][\d.]+(-\w+)?$`)
	// regex for check variable name
	varRegex = regexp.MustCompile(`^[a-zA-Z][\w-]*$`)
	// regex for check env var name
	envRegex = regexp.MustCompile(`^[A-Z][A-Z0-9_]*$`)
	// IsVariableName alias for IsVarName
	IsVariableName = IsVarName
	// regex for check uuid string. format: 8-4-4-4-12
	uuidPattern = regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`)
)

// IsVersion number. eg: 1.2.0
func ( string) bool { return verRegex.MatchString() }

// IsVarName is valid variable name.
func ( string) bool { return varRegex.MatchString() }

// IsEnvName is valid ENV var name. eg: APP_NAME
func ( string) bool { return envRegex.MatchString() }

// IsUUID check if the string is a valid UUID format.
func ( string) bool { return uuidPattern.MatchString() }

// Compare for two strings.
func (, ,  string) bool {
	switch  {
	case ">", "gt":
		return  > 
	case "<", "lt":
		return  < 
	case ">=", "gte":
		return  >= 
	case "<=", "lte":
		return  <= 
	case "!=", "ne", "neq":
		return  != 
	default: // eq
		return  == 
	}
}

// VersionCompare for two version strings. eg: 1.2.0 > 1.1.0
func (, ,  string) bool {
	 := parseVersion()
	 := parseVersion()

	 := compareVersions(, )
	switch  {
	case ">", "gt":
		return  > 0
	case "<", "lt":
		return  < 0
	case "=", "==", "eq":
		return  == 0
	case "!=", "ne", "neq":
		return  != 0
	case ">=", "gte":
		return  >= 0
	case "<=", "lte":
		return  <= 0
	default:
		return false
	}
}

// parseVersion 将版本号字符串解析为整数数组
func parseVersion( string) []int {
	if [0] == 'v' || [0] == 'V' {
		 = [1:]
	}

	// 处理 Git 描述格式: v1.7.1-16-gc43a587
	// 格式: <tag>-<commits>-g<hash>,其中 commits 表示距离 tag 的提交数
	var  int
	var  []int
	if  := strings.Index(, "-");  > 0 {
		 := [+1:]
		 = [:]
		// 尝试提取提交数(格式: 数字-g<hash> 或 数字)
		if  := strings.Index(, "-");  > 0 {
			if ,  := strconv.Atoi([:]);  == nil {
				 = 
			} else {
				 = parsePreRelease()
			}
		} else if ,  := strconv.Atoi();  == nil {
			 = 
		} else {
			 = parsePreRelease()
		}
	}

	 := strings.Split(, ".")
	 := make([]int, len())

	for ,  := range  {
		,  := strconv.Atoi()
		[] = 
	}

	// 如果有额外的提交数,追加到版本号末尾
	// 这样 v1.7.1-16-gc43a587 会变成 [1, 7, 1, 16]
	// 而 v1.7.1 是 [1, 7, 1],比较时前者更大
	if  > 0 {
		 = append(, )
	} else if len() > 0 {
		 = append(, ...)
	}

	return 
}

func parsePreRelease( string) []int {
	 = strings.ToLower()
	 := strings.Trim(, ".-")
	 := 0

	for ,  := range  {
		if  >= '0' &&  <= '9' {
			if ,  := strconv.Atoi(strings.Trim([:], ".-"));  == nil {
				 = 
			}
			 = strings.Trim([:], ".-")
			break
		}
	}

	 := 0
	switch  {
	case "a", "alpha":
		 = 1
	case "b", "beta":
		 = 2
	case "rc":
		 = 3
	}
	return []int{-1, , }
}

// compareVersions 比较两个版本号数组
// 返回: -1 表示 v1 < v2, 0 表示 v1 = v2, 1 表示 v1 > v2
func compareVersions(,  []int) int {
	 := len()
	if len() >  {
		 = len()
	}

	for  := 0;  < ; ++ {
		 := 0
		if  < len() {
			 = []
		}

		 := 0
		if  < len() {
			 = []
		}

		if  >  {
			return 1
		} else if  <  {
			return -1
		}
	}

	return 0
}

// SimpleMatch all substring in the give text string.
//
// Difference the ContainsAll:
//
//   - start with ^ for exclude contains check.
//   - end with $ for the check end with keyword.
func ( string,  []string) bool {
	for ,  := range  {
		 := len()
		if  == 0 {
			continue
		}

		// exclude
		if  > 1 && [0] == '^' {
			if strings.Contains(, [1:]) {
				return false
			}
			continue
		}

		// end with
		if  > 1 && [-1] == '$' {
			return strings.HasSuffix(, [:-1])
		}

		// include
		if !strings.Contains(, ) {
			return false
		}
	}
	return true
}

// QuickMatch check for a string. pattern can be a substring.
func (,  string) bool {
	if strings.ContainsRune(, '*') {
		return GlobMatch(, )
	}
	return strings.Contains(, )
}

// PathMatch check for a string match the pattern. alias of the path.Match()
//
// TIP: `*` can match any char, not contain `/`.
func (,  string) bool {
	,  := path.Match(, )
	if  != nil {
		 = false
	}
	return 
}

// GlobMatch check for a string match the pattern.
//
// Difference with PathMatch() is: `*` can match any char, contain `/`.
func (,  string) bool {
	// replace `/` to `S` for path.Match
	 = strings.Replace(, "/", "S", -1)
	 = strings.Replace(, "/", "S", -1)

	,  := path.Match(, )
	if  != nil {
		 = false
	}
	return 
}

// LikeMatch simple check for a string match the pattern. pattern like the SQL LIKE.
func (,  string) bool {
	 := len()
	if  < 2 {
		return false
	}

	// eg `%abc` `%abc%`
	if [0] == '%' {
		if  > 2 && [-1] == '%' {
			return strings.Contains(, [1:-1])
		}
		return strings.HasSuffix(, [1:])
	}

	// eg `abc%`
	if [-1] == '%' {
		return strings.HasPrefix(, [:-1])
	}
	return  == 
}

// MatchNodePath check for a string match the pattern.
//
// Use on a pattern:
//   - `*` match any to sep
//   - `**` match any to end. only allow at start or end on pattern.
//
// Example:
//
//	strutil.MatchNodePath()
func (,  string,  string) bool {
	if  == "**" ||  ==  {
		return true
	}
	if  == "" {
		return len() == 0
	}

	if  := strings.Index(, "**");  >= 0 {
		if  == 0 { // at start
			return strings.HasSuffix(, [2:])
		}
		return strings.HasPrefix(, [:len()-2])
	}

	 = strings.Replace(, , "/", -1)
	 = strings.Replace(, , "/", -1)

	,  := path.Match(, )
	if  != nil {
		 = false
	}
	return 
}