github.com/avicd/go-utilx@v0.1.0/conv/number.go (about)

     1  package conv
     2  
     3  import (
     4  	"math"
     5  	"strings"
     6  	"unicode"
     7  )
     8  
     9  type numInfo struct {
    10  	negative bool
    11  	base     int
    12  	integer  string
    13  	decimal  string
    14  }
    15  
    16  func isNumChar(r rune, base int) bool {
    17  	if base <= 10 {
    18  		return r >= '0' && r < '0'+rune(base)
    19  	} else {
    20  		return unicode.IsNumber(r) || r >= 'a' && r < 'a'+rune(base-10)
    21  	}
    22  }
    23  
    24  func parseNum(num string) *numInfo {
    25  	buf := strings.ToLower(num)
    26  	info := &numInfo{}
    27  	var cut int
    28  	if cut = strings.Index(buf, "+"); cut > -1 {
    29  		buf = buf[cut+1:]
    30  	}
    31  	if cut = strings.Index(buf, "-"); cut > -1 {
    32  		buf = buf[cut+1:]
    33  		info.negative = true
    34  	}
    35  	base := 10
    36  	tokens := map[string]int{"0b": 2, "0o": 8, "0x": 16}
    37  	for tk, bs := range tokens {
    38  		if cut = strings.Index(buf, tk); cut > -1 {
    39  			base = bs
    40  			buf = buf[cut+len(tk):]
    41  			break
    42  		}
    43  	}
    44  	info.base = base
    45  	valid := func(r rune) bool {
    46  		return isNumChar(r, base)
    47  	}
    48  	invalid := func(r rune) bool {
    49  		return !isNumChar(r, base)
    50  	}
    51  	if cut = strings.IndexFunc(buf, valid); cut > -1 {
    52  		buf = buf[cut:]
    53  	}
    54  	if cut = strings.IndexFunc(buf, invalid); cut > -1 {
    55  		info.integer = buf[:cut]
    56  		buf = buf[cut:]
    57  		if buf[0] == '.' {
    58  			buf = buf[1:]
    59  			if cut = strings.IndexFunc(buf, valid); cut > -1 {
    60  				if cut = strings.IndexFunc(buf, invalid); cut > -1 {
    61  					info.decimal = buf[:cut]
    62  				} else {
    63  					info.decimal = buf
    64  				}
    65  			}
    66  		}
    67  	} else {
    68  		info.integer = buf
    69  	}
    70  	return info
    71  }
    72  
    73  func parseDigit(r rune) int32 {
    74  	if r >= 'a' {
    75  		return r - 'a' + 10
    76  	} else if r <= '9' && r >= '0' {
    77  		return r - '0'
    78  	}
    79  	return 0
    80  }
    81  
    82  func ParseInt(input string) int64 {
    83  	info := parseNum(input)
    84  	high := len(info.integer)
    85  	var sum int64 = 0
    86  	var level int64 = 1
    87  	for _, ch := range info.integer {
    88  		high--
    89  		level = int64(math.Pow(float64(info.base), float64(high)))
    90  		sum += int64(parseDigit(ch)) * level
    91  	}
    92  	if info.negative {
    93  		sum = -sum
    94  	}
    95  	return sum
    96  }
    97  
    98  func ParseFloat(input string) float64 {
    99  	info := parseNum(input)
   100  	var sum = 0.0
   101  	high := len(info.integer)
   102  	plain := info.integer + info.decimal
   103  	for _, ch := range plain {
   104  		high--
   105  		level := math.Pow(float64(info.base), float64(high))
   106  		sum += float64(parseDigit(ch)) * level
   107  	}
   108  	if info.negative {
   109  		sum = -sum
   110  	}
   111  	return sum
   112  }