delphi 手机号码库段号地区查询


本文整理自网络,侵删。

 
手机号码库段号地区查询

 

一个用 Delphi  解析的手机号码库  例子,虽然现在可以手机号码不换号转网了,但可以用来学习 Delphi 流文件解析。和二叉树的快速查询

数据库来源:https://github.com/ls0f/phone

 

phone.dat文件格式

        | 4 bytes |                     <- phone.dat 版本号
        ------------
        | 4 bytes |                     <-  第一个索引的偏移
        -----------------------
        |  offset - 8            |      <-  记录区
        -----------------------
        |  index                 |      <-  索引区
        -----------------------

头部 头部为8个字节,版本号为4个字节,第一个索引的偏移为4个字节(<4si)。
记录区 中每条记录的格式为"<省份>|<城市>|<邮编>|<长途区号>\0"。 每条记录以'\0'结束。
索引区 中每条记录的格式为"<手机号前七位><记录区的偏移><卡类型>",每个索引的长度为9个字节(<iiB)。
解析步骤:

解析头部8个字节,得到索引区的第一条索引的偏移。
在索引区用二分查找得出手机号在记录区的记录偏移。
在记录区从上一步得到的记录偏移处取数据,直到遇到'\0'。
卡类型定义:

1 移动
2 联通
3 电信
4 电信虚拟运营商
5 联通虚拟运营商
6 移动虚拟运营商
 

 

 

 

 
 
 

 

 

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants
  , System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms
  , Vcl.Dialogs, Vcl.StdCtrls;

type

  TPhone = class(TObject)
  private
    FStm: TStringStream;
    FVersion: String;   //版本号
    FOffset: Cardinal; //起始偏移
  public
    function Find(const AStr7: String): String;
    constructor Create();
    destructor Destroy; override;
    procedure LoadFromFile(const FileName: string);
    property Version: String read FVersion;
  end;



  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    f: TPhone;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  StrUtils;


procedure TForm1.FormCreate(Sender: TObject);
begin
  f:= TPhone.Create;
  f.LoadFromFile(ExtractFilePath(ParamStr(0))+'phone.dat');
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  f.Free;
  f:= nil;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add( f.Find(Edit1.Text) );
end;


{ TPhone }

function TPhone.Find(Const AStr7: String): String;
  //查找记录的地区信息
  function GetArea(Idx:Int64):String;
  var
    Ansi: AnsiString;
    Buf: Byte;
  begin
    FStm.Position:= Idx;
    Buf:= 0;
    FStm.Read(Buf, 1);
    while (Buf <> 0) and (FStm.Position < FStm.Size)  do
    begin
      Ansi := Ansi + AnsiChar(Buf) ;
      FStm.Read(Buf, 1);
    end;
    GetArea:= '地区信息:' + UTF8ToString(Ansi);
  end;
type
  TRecord = Record
    Phone : Cardinal;//号码
    Idx : Cardinal;  //地址偏移
    CardType: Byte;  //卡类型
  end;
const
  FCount = 360569;
var
  Phone: Integer;//手机号
  L, R: Cardinal;//二叉树左右
  Idx: Integer;  //索引
  Rec: TRecord;
begin
  Result:= '';
  Phone:= StrToInt(LeftStr(AStr7, 7));//手机号
  case Phone of
    1300000..1399999,
    1500000..1599999,
    1800000..1899999,
    1450000..1459999,
    1470000..1479999,
    1700000..1709999,
    1760000..1769999,
    1770000..1779999:;
  else
    Result:= '你的手机号段在些库中尚未录入';
    Exit;
  end;

  L:= 0;
  R:= FCount;
  Idx:= (L+R) div 2;
  while Idx < FCount do begin
    FStm.Position:= FOffset + Idx * 9;
    FStm.Read(Rec, 9);
    if Rec.Phone = Phone then begin
      Result:= Result+ '手机前7位:'+IntToStr(Rec.Phone);
      case Rec.CardType of
        1: Result:= Result+ #13#10'卡类型:移动';
        2: Result:= Result+ #13#10'卡类型:联通';
        3: Result:= Result+ #13#10'卡类型:电信';
        4: Result:= Result+ #13#10'卡类型:电信虚拟运营商';
        5: Result:= Result+ #13#10'卡类型:联通虚拟运营商';
        6: Result:= Result+ #13#10'卡类型:移动虚拟运营商';
      end;
      Result:= Result+ #13#10 + GetArea(Rec.Idx);
      Exit;
    end
    else if Rec.Phone > Phone then begin
      R:= Idx;
    end
    else if Rec.Phone < Phone then begin
      L:= Idx;
    end;
    if L=R then begin
      Exit('未找到');
    end;
    Idx:=(L+R) div 2;
  end;
end;

procedure TPhone.LoadFromFile(const FileName: string);
var
  Ansi: Array[0..3] of AnsiChar;
begin
  FStm.LoadFromFile(FileName);
  FStm.Position:= 0;
  if FStm.Size > 0 then begin
    FStm.Read(Ansi, 4);
    FVersion:='版本号:'+ Ansi;
    FStm.Read(FOffset, 4);
  end;
end;

constructor TPhone.Create();
begin
  inherited;
  FStm:= TStringStream.Create;
end;

destructor TPhone.Destroy;
begin
  FStm.Free;
  FStm:= nil;
  inherited;
end;

end.
 
来源:http://delphifmx.com/node/15

相关阅读 >>

Delphi 屏蔽特殊字符

Delphi winapi: getfocus - 获取当前拥有焦点的窗口的句柄

Delphi 变体数组

Delphi thread类的创建及使用(关于线程函数的传递例子)

Delphi 10 seattle中录制音频

Delphi 一个中英文记录Delphi实现

Delphi 检查父进程

Delphi 代码查询一个json ip 地址的归属地

Delphi guid单元

Delphi 比较两个日期是否大于n天

更多相关阅读请进入《Delphi》频道 >>



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...