谈谈IMEI合法性判断方法

来源:互联网 发布:苹果cms火车头采集规则 编辑:程序博客网 时间:2024/06/11 14:10

1. 前言

本文简单介绍了IMEI的编码规则,然后引出IMEI校验的一个小程序,可作为C/C++编码爱好者的练手素材。


2. IMEI编码规则

2.1 IMEI组成

IMEI是由15个十进制数字组成的一个字符串,其中包括一个校验位(CD, Check Digit)。下面是3GPP TS23.003的几个截图:






简单地讲,IMEI一个15位,其中最后一位是CD(Check Digit)校验位。


2.2 CD位的计算方法



协议还提供了一个例子:


3. Luhn算法

在协议中,已经提到CD的计算方法是Luhn Algorithm。下面是维基百科对此的介绍:

  • 中文:http://zh.wikipedia.org/wiki/Luhn_algorithm
  • 英文:http://en.wikipedia.org/wiki/Luhn_algorithm

其中,英文链接中给出了Python语言的校验代码。


4. C/C++语言的校验程序

4.1 原型

在给出了上述背景知识之后,我们提出如下问题:用C/C++语言,写一个函数来检查IMEI号是否合法。原型如下:

/*   0: fail   1: ok*/int is_imei_valid(const char *imei);

4.2 参考代码

#include <stdio.h>#include <ctype.h>#include <string.h>const int IMEI_LENGTH = 15;/*  Get the check digit of Luhn algorithm.  data: the digits to be checked. The last digit is the CD.  len: the length of data/digits.  return:    -1: error occurs    others('0'..'9'): the check digit*/int luhn_checksum(const char *data, int len){    if (data == NULL || len < 2) return -1;    int even = 1;    int sum = 0;    int double_digit;     char p;    int i;    for (i = len - 2; i >= 0; i--) {        p = data[i];        if (!isdigit(p)) return -1;        p -= '0';        if (even) {            double_digit = p + p;             sum += double_digit / 10 + double_digit % 10;        } else {            sum += p;        }        even = !even;    }    return sum * 9 % 10;}/*  return:    -1: error occurs    others('0'..'9'): the check digit*/int get_imei_cd(const char *imei){    if (imei == NULL) return -1;    if (strlen(imei) != IMEI_LENGTH) return -1;    int cd = luhn_checksum(imei, IMEI_LENGTH);    return cd == -1 ? -1 : cd + '0';}/*   0: fail   1: ok*/int is_imei_valid(const char *imei){    int cd = get_imei_cd(imei);    if (cd == -1) return 0;    return imei[IMEI_LENGTH - 1] == cd;}void test_is_imei_valid(const char *testcaseName, const char *imei, int expect){    printf("TESTCASE----%s: ", testcaseName);    int result = is_imei_valid(imei);    if (result == expect) {        printf("PASS\n");    } else {        printf("FAIL. expect=%d, real=%d\n", expect, result);    }}void test_get_imei_cd(const char *testcaseName, const char *imei, int expect){    printf("TESTCASE----%s: ", testcaseName);    int result = get_imei_cd(imei);    if (result == expect) {        printf("PASS\n");    } else {        printf("FAIL. expect=0x%02x, real=0x%02x\n", expect, result);    }}int main(){    printf("test_is_imei_valid\n");    test_is_imei_valid("valid imei 000000000000000", "000000000000000", 1);    test_is_imei_valid("valid imei 012550003170164", "012550003170164", 1);    test_is_imei_valid("valid imei 123412341234564", "123412341234564", 1);    test_is_imei_valid("null imei", NULL, 0);    test_is_imei_valid("invalid imei", "123412341234567", 0);    test_is_imei_valid("invalid imei", "12341234123456", 0);    test_is_imei_valid("invalid imei", "1234123412345678", 0);    printf("test_get_imei_cd\n");    test_get_imei_cd("valid imei 000000000000000", "000000000000000", '0');    test_get_imei_cd("valid imei 012550003170164", "012550003170164", '4');    test_get_imei_cd("valid imei 123412341234564", "123412341234564", '4');    test_get_imei_cd("null imei", NULL, -1);    test_get_imei_cd("invalid imei", "12341234123456", -1);    test_get_imei_cd("invalid imei", "1234123412345678", -1);    return 0;}

运行结果:

flying-bird@flyingbird:~/docs/The_Road_to_Cpp/src/imei$ gcc imei.cflying-bird@flyingbird:~/docs/The_Road_to_Cpp/src/imei$ ./a.out test_is_imei_validTESTCASE----valid imei 000000000000000: PASSTESTCASE----valid imei 012550003170164: PASSTESTCASE----valid imei 123412341234564: PASSTESTCASE----null imei: PASSTESTCASE----invalid imei: PASSTESTCASE----invalid imei: PASSTESTCASE----invalid imei: PASStest_get_imei_cdTESTCASE----valid imei 000000000000000: PASSTESTCASE----valid imei 012550003170164: PASSTESTCASE----valid imei 123412341234564: PASSTESTCASE----null imei: PASSTESTCASE----invalid imei: PASSTESTCASE----invalid imei: PASSflying-bird@flyingbird:~/docs/The_Road_to_Cpp/src/imei$ 



0 0
原创粉丝点击