Skip to content

Instantly share code, notes, and snippets.

@otabekoff
Forked from yetimdasturchi/howto.md
Created June 4, 2025 10:54
Show Gist options
  • Save otabekoff/478d26a47bfc6276be0158fd5007fa99 to your computer and use it in GitHub Desktop.
Save otabekoff/478d26a47bfc6276be0158fd5007fa99 to your computer and use it in GitHub Desktop.
Uzbekistan ID Card MRZ Parser

ID card parser

Compiling:

gcc id_card_parser.c -o passport_data

Usage:

 ./passport_data $'IUUZBAD9876543210998877554433<\n9506229F7896543XXXUZB<<<<<<<<9\nESHMATOV<<TOSHMAT<<<<<<<<<<<<<'
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int is_valid_passport_line(const char *line) {
for (int i = 0; line[i]; i++) {
if (!(isupper(line[i]) || isdigit(line[i]) || line[i] == '<')) {
return 0;
}
}
return 1;
}
int parse_dob_gender_country(const char *line2, char *dob, char *gender, char *countryCode) {
if (strlen(line2) < 10) return 0;
strncpy(dob, line2, 6);
dob[6] = '\0';
*gender = line2[7];
strncpy(countryCode, line2 + 8, 3);
countryCode[3] = '\0';
return 1;
}
void format_date(const char *dob, char *formattedDate) {
int year = atoi((char[]){dob[0], dob[1], '\0'});
char fullYear[5];
if (year <= 21) {
sprintf(fullYear, "20%02d", year);
} else {
sprintf(fullYear, "19%02d", year);
}
char month[3] = {dob[2], dob[3], '\0'};
char day[3] = {dob[4], dob[5], '\0'};
sprintf(formattedDate, "%s-%s-%s", fullYear, month, day);
}
int parse_name_line(const char *line3, char *lastName, char *firstName) {
const char *sep = strstr(line3, "<<");
if (!sep) return 0;
int lenLast = sep - line3;
strncpy(lastName, line3, lenLast);
lastName[lenLast] = '\0';
const char *firstStart = sep + 2;
const char *end = strstr(firstStart, "<<");
if (!end) end = firstStart + strlen(firstStart);
strncpy(firstName, firstStart, end - firstStart);
firstName[end - firstStart] = '\0';
return 1;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s $'<passport_text_with_\\n_lines>'\n", argv[0]);
return 1;
}
char *text = argv[1];
char *line1 = strtok(text, "\n");
char *line2 = strtok(NULL, "\n");
char *line3 = strtok(NULL, "\n");
if (!line1 || !line2 || !line3) {
printf("Passport data should consist of exactly 3 lines.\n");
return 1;
}
if (!is_valid_passport_line(line1)) {
printf("Invalid characters in the passport number (Line 1).\n");
return 1;
}
char dob[7], gender, countryCode[4];
if (!parse_dob_gender_country(line2, dob, &gender, countryCode)) {
printf("Line 2 is not in the correct format (YYMMDD, gender, country code).\n");
return 1;
}
char formattedDate[11];
format_date(dob, formattedDate);
char lastName[50], firstName[50];
if (!parse_name_line(line3, lastName, firstName)) {
printf("Line 3 is not in the correct format (LastName<<FirstName).\n");
return 1;
}
printf("Passport Data:\n");
printf("Passport Number: %s\n", line1);
printf("Date of Birth: %s\n", formattedDate);
printf("Gender: %c\n", gender);
printf("Country Code: %s\n", countryCode);
printf("Last Name: %s\n", lastName);
printf("First Name: %s\n", firstName);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment