Skip to content

号段查询(使用qqzeng)

官网:https://www.qqzeng.com/

  • v3版本qqzeng-phone-3.0.dat 下载
  • v5版本qqzeng-phone-5.0.dat 下载

v3版本

集成工具类示例:

go
package qqzengphone

/**
@author: liqiang@konyun.net
参考原作者代码整理,已测试
**/

import (
	"callcenter_backend/pkg/logger"
	"encoding/binary"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type QqzengPhoneV3 struct {
	data    []byte
	phone2D [][]int
	addrArr []string
	ispArr  []string
}

func NewQqzengPhoneV3(filepath string) (*QqzengPhoneV3, error) {
	data, err := os.ReadFile(filepath)
	if err != nil {
		logger.Errorf("Error reading the dat file:%v", err)
		return nil, err
	}
	PrefSize := binary.LittleEndian.Uint32(data[0:4])
	descLength := binary.LittleEndian.Uint32(data[8:12])
	ispLength := binary.LittleEndian.Uint32(data[12:16])
	headLength := 20
	startIndex := headLength + int(descLength) + int(ispLength)
	// Description array
	descString := string(data[headLength : headLength+int(descLength)])
	addrArr := strings.Split(descString, "&")
	// ISP array
	ispString := string(data[headLength+int(descLength) : headLength+int(descLength)+int(ispLength)])
	ispArr := strings.Split(ispString, "&")
	// Phone2D array
	phone2D := make([][]int, 200)
	for m := 0; m < int(PrefSize); m++ {
		i := m*7 + startIndex
		pref := int(data[i])
		index := int(binary.LittleEndian.Uint32(data[i+1 : i+5]))
		length := int(binary.LittleEndian.Uint16(data[i+5 : i+7]))

		phone2D[pref] = make([]int, 10000)
		for n := 0; n < length; n++ {
			p := startIndex + int(PrefSize)*7 + (n+index)*4
			suff := int(binary.LittleEndian.Uint16(data[p : p+2]))
			addrispIndex := int(binary.LittleEndian.Uint16(data[p+2 : p+4]))
			phone2D[pref][suff] = addrispIndex
		}
	}
	return &QqzengPhoneV3{
		data:    data,
		phone2D: phone2D,
		addrArr: addrArr,
		ispArr:  ispArr,
	}, nil
}

func (psb *QqzengPhoneV3) Get(phone string) string {
	prefix := phone[:3]
	suffix := phone[3:7]
	pref, _ := strconv.Atoi(prefix)
	suff, _ := strconv.Atoi(suffix)
	addrispIndex := psb.phone2D[pref][suff]
	if addrispIndex == 0 {
		return ""
	}
	addr := psb.addrArr[addrispIndex/100]
	isp := psb.ispArr[addrispIndex%100]
	return fmt.Sprintf("%s|%s", addr, isp)
}

调用示例:

go
package qqzengphone

/**
@author: liqiang@konyun.net
**/

import (
	"fmt"
	"testing"
)

func TestQqzengv3(t *testing.T) {
	filePath := "/Users/van/go_workspace/callcenter/callcenter_backend/uploads/qqzeng-phone-3.0.dat"
	finder, err := NewQqzengPhoneV3(filePath)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	phone := "13872295563"
	result := finder.Get(phone)
	fmt.Println(phone)
	fmt.Println(result)
}

v5版本

集成工具类示例:

go
package qqzengphone

/**
@author: liqiang@konyun.net
参考原作者java代码整理,已测试
**/

import (
	"callcenter_backend/pkg/logger"
	"encoding/binary"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type QqzengPhoneV5 struct {
	prefmap  [200][2]uint32
	phonemap [][2]uint32
	phoneArr []uint32
	addrArr  []string
	ispArr   []string
}

func NewQqzengPhoneV5(path string) (*QqzengPhoneV5, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, err
	}

	var prefSize, recordSize, descLength, ispLength uint32
	prefSize = binary.LittleEndian.Uint32(data[:4])
	recordSize = binary.LittleEndian.Uint32(data[4:8])
	descLength = binary.LittleEndian.Uint32(data[8:12])
	ispLength = binary.LittleEndian.Uint32(data[12:16])

	descOffset := int(16 + prefSize*9 + recordSize*7)
	descString := string(data[descOffset : descOffset+int(descLength)])
	addrArr := strings.Split(descString, "&")

	ispOffset := descOffset + int(descLength)
	ispString := string(data[ispOffset : ispOffset+int(ispLength)])
	ispArr := strings.Split(ispString, "&")
	var prefmap [200][2]uint32
	for k := 0; k < int(prefSize); k++ {
		i := k*9 + 16
		n := uint32(data[i]) & 0xFF
		prefmap[n][0] = binary.LittleEndian.Uint32(data[i+1 : i+5])
		prefmap[n][1] = binary.LittleEndian.Uint32(data[i+5 : i+9])
	}
	phoneArr := make([]uint32, int(recordSize))
	phonemap := make([][2]uint32, int(recordSize))
	for i := 0; i < int(recordSize); i++ {
		p := 16 + int(prefSize)*9 + i*7
		phoneArr[i] = BytesToLong(data[p], data[1+p], data[2+p], data[3+p])
		phonemap[i][0] = BytesToLong(data[4+p], data[5+p], byte(0), byte(0))
		phonemap[i][1] = BytesToLong(data[6+p], byte(0), byte(0), byte(0))
	}
	return &QqzengPhoneV5{
		prefmap:  prefmap,
		phonemap: phonemap,
		phoneArr: phoneArr,
		addrArr:  addrArr,
		ispArr:   ispArr,
	}, nil
}

func BytesToLong(a, b, c, d byte) uint32 {
	var bytes [4]byte
	bytes[0] = a
	bytes[1] = b
	bytes[2] = c
	bytes[3] = d
	var num uint32
	binary.BigEndian.PutUint32(bytes[:], uint32(a)|(uint32(b)<<8)|(uint32(c)<<16)|(uint32(d)<<24))
	num = uint32(binary.BigEndian.Uint32(bytes[:]))
	return num
}

func (p *QqzengPhoneV5) Get(phone string) string {
	prefStr := phone[:3]
	valStr := phone[:7]
	pref, err := strconv.Atoi(prefStr)
	if err != nil {
		logger.Errorf("err:%v", err)
	}
	val, err := strconv.Atoi(valStr)
	if err != nil {
		logger.Errorf("err:%v", err)
	}
	low := int(p.prefmap[pref][0])
	high := int(p.prefmap[pref][1])
	if high == 0 {
		return ""
	}
	cur := p.binarySearch(low, high, uint32(val))
	if cur != -1 {
		return fmt.Sprintf("%s|%s", p.addrArr[p.phonemap[cur][0]], p.ispArr[p.phonemap[cur][1]])
	}
	return ""
}

func (p *QqzengPhoneV5) binarySearch(low, high int, k uint32) int {
	M := 0
	for low <= high {
		mid := (low + high) / 2
		phoneNumber := p.phoneArr[mid]
		if phoneNumber >= k {
			M = mid
			if mid == 0 {
				break
			}
			high = mid - 1
		} else {
			low = mid + 1
		}
	}
	return M
}

调用示例:

go
package qqzengphone

/**
@author: liqiang@konyun.net
**/

import (
	"fmt"
	"testing"
)

func TestQqzengv5(t *testing.T) {
	filePath := "/Users/van/go_workspace/callcenter/callcenter_backend/uploads/qqzeng-phone-5.0.dat"
	finder, err := NewQqzengPhoneV5(filePath)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	phone := "13872295563"
	result := finder.Get(phone)
	fmt.Println(phone)
	fmt.Println(result)
}