谈谈IMEI合法性判断方法

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。下面是维基百科对此的介绍:

其中,英文链接中给出了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.c
flying-bird@flyingbird:~/docs/The_Road_to_Cpp/src/imei$ ./a.out 
test_is_imei_valid
TESTCASE----valid imei 000000000000000: PASS
TESTCASE----valid imei 012550003170164: PASS
TESTCASE----valid imei 123412341234564: PASS
TESTCASE----null imei: PASS
TESTCASE----invalid imei: PASS
TESTCASE----invalid imei: PASS
TESTCASE----invalid imei: PASS
test_get_imei_cd
TESTCASE----valid imei 000000000000000: PASS
TESTCASE----valid imei 012550003170164: PASS
TESTCASE----valid imei 123412341234564: PASS
TESTCASE----null imei: PASS
TESTCASE----invalid imei: PASS
TESTCASE----invalid imei: PASS
flying-bird@flyingbird:~/docs/The_Road_to_Cpp/src/imei$ 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值