Вам приходилось писать тех.задание для программистов? Нет? Ах, вы сами пишите программы :-) ... я тоже, конечно, нет, нет, да что-нибудь напишу. Но в основной своей массе мне приходиться объяснять нашим разработчикам ЧТО же нам надо (иногда доходит до абсурда - говоришь уже конкретный программный код :-)) Вот и в этот раз возникла задача описать алгоритмически процесс проверки ИНН юридических и физических лиц, а так же ОГРН юридических лиц и ОГРНИП физических лиц - индивидуальных предпринимателей. Задача, по-сути, тривиальная и, к тому же, алгоритмы проверки найти в интернете не составляет труда. Тем не менее, что бы лишний раз удостовериться в корректности найденных алгоритмов (и иметь рабочую программную версию) было принято решение предварительно реализовать их самостоятельно на языке C++. Что из этого получилось - смотрите ниже.
Конечно, я осознаю, что это реализация не в духе "чистого" C++, поэтому любые комментарии и оптимизации приветствуются :-).
Итак, вашему вниманию предлагаю алгоритмы проверки ИНН, ОГРН, ОГРНИП (дабы вы лишний раз не утруждали себя поиском ;-)), а так же функции их практической реализации.
В процессе написания функций проверки потребовалось преобразование типов из string в int и double. Встроенных инструментов для этих целей C++ не предлагает, кроме средств C библиотеки: atoi() и т.п. Поэтому была написана дополнительная функция неявного преобразования (посредством stringstream), возможно решение не очень изящное, но вполне рабочее :).
template <class T> T str_to_dig(string str)
{
stringstream sstr;
T dig_val;
if (str.empty())
return 0;
sstr << str;
sstr >> dig_val;
return dig_val;
}
Проверка ИНН юридического лица.
Алгоритм проверки:
1. Необходимо вычислить контрольную сумма ИНН с весовыми коэффициентами: [2,4,10,3,5,9,4,6,8,0] (для этого каждый разряд ИНН умножается на соответствующий коэффициент: 1-ый разряд на 2, 2-ой на 4 и т.д.).
2. Затем вычисляется контрольное число, как остаток от деления контрольной суммы на 11.
3. В случае, если контрольное число больше 9, то контрольное число необходимо дополнительно вычислить как остаток от деления контрольного числа (вычисленного в п.2) на 10.
4. Полученное контрольное число сравнивается с 10 знаком ИНН, в случае их равенства - ИНН считается корректным.
Функция проверки:
int inn10_check(string *inn)
{
//Ошибки возвращаемые функцией:
// 1 - неверная длина ИНН
// 2 - в номере ИНН некорректный символ (отличный от 0..9)
// 3 - ИНН не правильный
// В случае корректного ИНН возвращается 0
if (inn->length() != 10) return 1;
int summ(0), ost(0), weights[10] = {2,4,10,3,5,9,4,6,8,0};
string digit;
for (int i = 0; i < 10; i++)
{
if (!isdigit(inn->at(i))) return 2;
digit = inn->at(i);
summ += str_to_dig<int> (digit)*weights[i];
}
ost = summ%11;
if (ost > 9) ost = ost%10;
if (ost == str_to_dig<int> (digit)) return 0;
return 3;
}
Проверка ИНН физического лица
Алгоритм проверки:Проверка ИНН физического лица осуществляется на основе вычисления 2-х контрольных чисел.
1. Подсчитывается контрольная сумма для первых 11-ти знаков ИНН со следующими весовыми коэффициентами: [7,2,4,10,3,5,9,4,6,8,0] (для этого каждый разряд ИНН умножается на соответствующий коэффициент: 1-ый разряд на 7, 2-ой на 2 и т.д.).
2. Вычисляется первое контрольное число (КЧ1) как остаток от деления контрольной суммы (из п.1) на 11.
3. В случае, если КЧ1 больше 9, то вычисляется новое КЧ1 как остаток от деления КЧ1 на 10.
4. Подсчитывается контрольная сумма для всех 12-ти знаков ИНН со следующими весовыми коэффициентами [3,7,2,4,10,3,5,9,4,6,8,0].
5. Вычисляется второе контрольное число (КЧ2) как остаток от деления контрольной суммы (из п.4) на 11.
6. В случае, если КЧ2 больше 9, то вычисляется новое КЧ2 как остаток от деления КЧ2 на 10.
7. Полученные контрольные числа КЧ1 и КЧ2 сравниваются с 11 и 12 знаками ИНН соответственно. В случае их равенства - ИНН корректен.
Функция проверки:
int inn12_check(string *inn)
{
//Ошибки возвращаемые функцией:
// 1 - неверная длина ИНН
// 2 - в номере ИНН некорректный символ (отличный от 0..9)
// 3 - ИНН не правильный
// В случае корректного ИНН возвращается 0
if (inn->length() != 12) return 1;
int summ(0), ost1(0), ost2(0);
int weights1[11] = {7,2,4,10,3,5,9,4,6,8,0};
int weights2[12] = {3,7,2,4,10,3,5,9,4,6,8,0};
string digit;
for (int i = 0; i < 12; i++)
{
if (!isdigit(inn->at(i))) return 2;
digit = inn->at(i);
summ += str_to_dig<int> (digit)*weights2[i];
}
ost2 = summ%11;
if (ost2 > 9) ost2 = ost2%10;
summ = 0;
for (int i = 0; i < 11; i++)
{
digit = inn->at(i);
summ += str_to_dig<int> (digit)*weights1[i];
}
ost1 = summ%11;
if (ost1 > 9) ost1 = ost1%10;
if (ost1 == str_to_dig<int> (digit))
{
digit = inn->at(11);
if (ost2 == str_to_dig<int> (digit)) return 0;
}
return 3;
}
Проверка ОГРН юридического лица
Алгоритм проверки:1. Вычисляется контрольное число как остаток от деления числа состоящего из первых 12 знаков ОГРН на 11.
2. В случае, если контрольное число больше 9, то вычисляется новое контрольное число как остаток от деления контрольного числа (из п. 1) на 10.
3. Контрольное число сравнивается с 13 знаком ОГРН, в случае их равенства ОГРН считается корректным.
Функция проверки:
int ogrn13_check(string *ogrn)
{
//Ошибки возвращаемые функцией:
// 1 - неверная длина ОГРН
// 2 - в номере ОГРН некорректный символ (отличный от 0..9)
// 3 - ОГРН не правильный
// В случае корректного ОГРН возвращается 0
// ВНИМАНИЕ: в функции используется тип double!
if (ogrn->length() != 13) return 1;
double d1(0);
int ost(0);
string digit;
for (int i=0; i < 13; i++)
{
if (!isdigit(ogrn->at(i))) return 2;
}
d1 = str_to_dig<double> (ogrn->substr(0,12));
ost = d1 - (floor(d1/11))*11;
if (ost > 9) ost = ost%10;
digit = ogrn->at(12);
if (ost == str_to_dig<int> (digit)) return 0;
return 3;
}
Проверка ОГРНИП физического лица - индивидуального предпринимателя
Алгоритм проверки: 1. Вычисляется контрольное число как остаток от деления числа состоящего из первых 14 знаков ОГРНИП на 13.
2. В случае, если контрольное число больше 9, то вычисляется новое контрольное число как остаток от деления контрольного числа (из п. 1) на 10.
3. Контрольное число сравнивается с 15 знаком ОГРНИП, в случае их равенства ОГРНИП считается корректным.
Функция проверки:
int ogrn15_check(string *ogrn)
{
//Ошибки возвращаемые функцией:
// 1 - неверная длина ОГРНИП
// 2 - в номере ОГРНИП некорректный символ (отличный от 0..9)
// 3 - ОГРНИП не правильный
// В случае корректного ОГРНИП возвращается 0
// ВНИМАНИЕ: в функции используется тип double!
if (ogrn->length() != 15) return 1;
double d1(0);
int ost(0);
string digit;
for (int i=0; i < 15; i++)
{
if (!isdigit(ogrn->at(i))) return 2;
}
d1 = str_to_dig<double> (ogrn->substr(0,14));
ost = d1 - (floor(d1/13))*13;
if (ost > 9) ost = ost%10;
digit = ogrn->at(14);
if (ost == str_to_dig<int> (digit)) return 0;
return 3;
}
Как видно из функций проверки ОГРН/ОГРНИП, алгоритмы не сильно разнятся друг от друга (в отличии от алгоритмов проверки ИНН), поэтому резонно возникает вопрос - "Можно ли их объединить в одну функцию?". Все можно, если очень захотеть :-). Свой вариант такой функции вам предложить готов и я:
//обобщенная функция проверки ОГРН/ОГРНИП, в качестве второго
//аргумента принимает значение характеризующее тип проверяемого
//регистрационного номера: 0 - ОГРН, 1 - ОГРНИП
//по-умолчанию проверяется ОГРН
int ogrn_check(string *, int ogrn_type = 0);
int ogrn_check(string *ogrn, int ogrn_type)
{
//Ошибки возвращаемые функцией:
// 1 - не верно указан тип проверяемого ОГРН/ОГРНИП
// 2 - неверная длина ОГРН/ОГРНИП
// 3 - в номере ОГРН/ОГРНИП некорректный символ (отличный от 0..9)
// 4 - ОГРН/ОГРНИП не правильный
// В случае корректного ОГРН/ОГРНИП возвращается 0
// ВНИМАНИЕ: в функции используется тип double!
unsigned int ogrn_length(13), ogrn_div(11), ost(0);
double d1;
string digit;
switch (ogrn_type)
{
case 0:
break;
case 1:
ogrn_length = 15;
ogrn_div = 13;
break;
default: return 1;
}
if (ogrn->length() != ogrn_length) return 2;
for (unsigned int i = 0; i < ogrn_length; i++)
{
if (!isdigit(ogrn->at(i))) return 3;
}
d1 = str_to_dig<double> (ogrn->substr(0,(ogrn_length-1)));
ost = d1 - (floor(d1/ogrn_div))*ogrn_div;
if (ost > 9) ost = ost%10;
digit = ogrn->at(ogrn_length-1);
if (ost == str_to_dig<unsigned int>(digit)) return 0;
return 4;
}
В заключении следует указать необходимые заголовочные файлы, требуемые для указанных функций, как говорится "на всякий случай" :-):
#include <iostream>
#include <string>
#include <sstream>
#include <cmath>
На этом все - спасибо всем за внимание ;-).
СПА-СИ-БО!! Огромнейшее!! Считается ,что в интернете масса готового кода по расчету ИИН, а вот и нетушкки!! Я вас аж на 3-й странице поиска нашла! И что б на С++ было. Не пропадайте! Вы нам очень нужны!
ОтветитьУдалитьпремного благодарен
ОтветитьУдалить