marion 4 years ago
parent
commit
fa3cbe1e87
1 changed files with 146 additions and 0 deletions
  1. 146 0
      utils/phone.go

+ 146 - 0
utils/phone.go

@@ -0,0 +1,146 @@
+/*
+* Copyright (c) 2015, zheng-ji.info
+* */
+package gophone
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+const (
+	IntLen           = 4
+	CharLen          = 1
+	PhoneIndexLength = 9
+	Chunk            = 100
+)
+
+type GOPhone struct {
+	phoneDat []byte
+}
+
+type PhoneRecord struct {
+	PhoneNum string
+	Province string
+	City     string
+	ZipCode  string
+	AreaZone string
+	CardType string
+}
+
+func New(phoneDat []byte) *GOPhone {
+	if nil == phoneDat || len(phoneDat) == 0 {
+		panic(errors.New("phoneDat is required"))
+	}
+	return &GOPhone{
+		phoneDat: phoneDat,
+	}
+}
+
+func (g *GOPhone) Display() {
+	fmt.Println(g.getVersion())
+	fmt.Println(g.getTotalRecord())
+	fmt.Println(g.getFirstRecordOffset())
+}
+
+func (pr PhoneRecord) String() string {
+	_str := fmt.Sprintf("PhoneNum: %s\nAreaZone: %s\nCardType: %s\nCity: %s\nZipCode: %s\nProvince: %s\n", pr.PhoneNum, pr.AreaZone, pr.CardType, pr.City, pr.ZipCode, pr.Province)
+	return _str
+}
+
+func (g *GOPhone) getVersion() string {
+	return string(g.phoneDat[0:IntLen])
+}
+
+func (g *GOPhone) getTotalRecord() int32 {
+	total := (int32(len(g.phoneDat)) - g.getFirstRecordOffset()) / PhoneIndexLength
+	return total
+}
+
+func (g *GOPhone) getFirstRecordOffset() int32 {
+	var offset int32
+	buffer := bytes.NewBuffer(g.phoneDat[IntLen : IntLen*2])
+	_ = binary.Read(buffer, binary.LittleEndian, &offset)
+	return offset
+}
+
+func (g *GOPhone) getIndexRecord(offset int32) (phonePrefix int32, recordOffset int32, cardType byte) {
+	buffer := bytes.NewBuffer(g.phoneDat[offset : offset+IntLen])
+	_ = binary.Read(buffer, binary.LittleEndian, &phonePrefix)
+	buffer = bytes.NewBuffer(g.phoneDat[offset+IntLen : offset+IntLen*2])
+	_ = binary.Read(buffer, binary.LittleEndian, &recordOffset)
+	buffer = bytes.NewBuffer(g.phoneDat[offset+IntLen*2 : offset+IntLen*2+CharLen])
+	_ = binary.Read(buffer, binary.LittleEndian, &cardType)
+	return
+}
+
+func (g *GOPhone) getOpCompany(cardtype byte) string {
+	var cardStr = ""
+	switch cardtype {
+	case '1':
+		cardStr = "移动"
+	case '2':
+		cardStr = "联通"
+	case '3':
+		cardStr = "电信"
+	case '4':
+		cardStr = "电信虚拟运营商"
+	case '5':
+		cardStr = "联通虚拟运营商"
+	default:
+		cardStr = "移动虚拟运营商"
+	}
+	return cardStr
+}
+
+// BinarySearch
+func (g *GOPhone) Find(phoneNum string) (pr *PhoneRecord, err error) {
+	err = nil
+	if len(phoneNum) < 7 || len(phoneNum) > 11 {
+		return nil, errors.New("illegal phone length")
+	}
+
+	var left int32 = 0
+	phoneSevenInt, _ := strconv.ParseInt(phoneNum[0:7], 10, 32)
+	phoneSevenInt32 := int32(phoneSevenInt)
+	totalLen := int32(len(g.phoneDat))
+	right := g.getTotalRecord()
+	firstPhoneRecordOffset := g.getFirstRecordOffset()
+	for {
+		if left > right {
+			break
+		}
+		mid := (left + right) / 2
+		currentOffset := firstPhoneRecordOffset + mid*PhoneIndexLength
+
+		if currentOffset >= totalLen {
+			break
+		}
+		curPhone, recordOffset, cardType := g.getIndexRecord(currentOffset)
+		if curPhone > phoneSevenInt32 {
+			right = mid - 1
+		} else if curPhone < phoneSevenInt32 {
+			left = mid + 1
+		} else {
+			s := recordOffset
+			e := recordOffset + int32(strings.Index(string(g.phoneDat[recordOffset:recordOffset+Chunk]), "\000"))
+			recordContent := string(g.phoneDat[s:e])
+			_tmp := strings.Split(recordContent, "|")
+			cardStr := g.getOpCompany(cardType)
+			pr = &PhoneRecord{
+				PhoneNum: phoneNum,
+				Province: _tmp[0],
+				City:     _tmp[1],
+				ZipCode:  _tmp[2],
+				AreaZone: _tmp[3],
+				CardType: cardStr,
+			}
+			return
+		}
+	}
+	return nil, errors.New("num not found")
+}