Skip to content

Commit 2494a43

Browse files
authored
SEL-559: Update td1 regex (#760)
* feat: update td1 regex * update review comments * fix: NPE on expirationDate regex
1 parent 83d016e commit 2494a43

File tree

1 file changed

+57
-1
lines changed
  • app/android/android-passport-reader/app/src/main/java/example/jllarraz/com/passportreader/utils

1 file changed

+57
-1
lines changed

app/android/android-passport-reader/app/src/main/java/example/jllarraz/com/passportreader/utils/OcrUtils.kt

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ object OcrUtils {
2121
private val REGEX_TD1_LINE2 = "(?<dateOfBirth>[0-9]{6})(?<checkDigitDateOfBirth>[0-9]{1})(?<sex>[FM<]{1})(?<expirationDate>[0-9]{6})(?<checkDigitExpiration>[0-9]{1})(?<nationality>[A-Z<]{3})(?<optionalData2>[A-Z0-9<]{7})"
2222
private val REGEX_TD1_LINE3 ="(?<names>[A-Z<]{30})"
2323

24+
// TD1 (ID Card)
25+
private val REGEX_ID_DOCUMENT_CODE = "(?<documentCode>[IP]{1}[DM<]{1})"
26+
private val REGEX_ID_DOCUMENT_NUMBER = "(ID)(?<country>[A-Z<]{3})(?<documentNumber>[A-Z0-9<]{9})(?<checkDigitDocumentNumber>[0-9]{1})"
27+
private val REGEX_ID_DATE_OF_BIRTH = "(?<dateOfBirth>[0-9]{6})(?<checkDigitDateOfBirth>[0-9]{1})(?<gender>[FM<]{1})"
28+
29+
private val patternDocumentNumber = Pattern.compile(REGEX_ID_DOCUMENT_NUMBER)
30+
private val patternDateOfBirth = Pattern.compile(REGEX_ID_DATE_OF_BIRTH)
31+
private val patternDocumentCode = Pattern.compile(REGEX_ID_DOCUMENT_CODE)
32+
33+
2434
fun processOcr(
2535
results: Text,
2636
timeRequired: Long,
@@ -47,11 +57,57 @@ object OcrUtils {
4757
val patternTD1Line2 = Pattern.compile(REGEX_TD1_LINE2)
4858
val patternTD1Line3 = Pattern.compile(REGEX_TD1_LINE3)
4959

60+
5061
val matcherTD1Line1 = patternTD1Line1.matcher(fullRead)
5162
val matcherTD1Line2 = patternTD1Line2.matcher(fullRead)
5263
val matcherTD1Line3 = patternTD1Line3.matcher(fullRead)
5364

65+
val matcherDocumentCode = patternDocumentCode.matcher(fullRead)
66+
67+
if (matcherDocumentCode.find() && matcherDocumentCode.group("documentCode") == "ID") {
68+
Log.d(TAG, "ID card found")
69+
70+
val matcherDocumentNumber = patternDocumentNumber.matcher(fullRead)
71+
val matcherDateOfBirth = patternDateOfBirth.matcher(fullRead)
72+
73+
val hasDocumentNumber = matcherDocumentNumber.find()
74+
val hasDateOfBirth = matcherDateOfBirth.find()
75+
76+
val documentNumber = if (hasDocumentNumber) matcherDocumentNumber.group("documentNumber") else null
77+
val checkDigitDocumentNumber = if (hasDocumentNumber) matcherDocumentNumber.group("checkDigitDocumentNumber")?.toIntOrNull() else null
78+
val countryCode = if (hasDocumentNumber) matcherDocumentNumber.group("country") else null
79+
val dateOfBirth = if (hasDateOfBirth) matcherDateOfBirth.group("dateOfBirth") else null
80+
val checkDigitDateOfBirth = if (hasDateOfBirth) matcherDateOfBirth.group("checkDigitDateOfBirth")?.toIntOrNull() else null
81+
val gender = if (hasDateOfBirth) matcherDateOfBirth.group("gender") else null
82+
83+
val expirationDate: String? = if (!countryCode.isNullOrEmpty()) {
84+
val expirationDateRegex = "(?<expirationDate>[0-9]{6})(?<checkDigitExpiration>[0-9]{1})" + Pattern.quote(countryCode)
85+
val patternExpirationDate = Pattern.compile(expirationDateRegex)
86+
val matcherExpirationDate = patternExpirationDate.matcher(fullRead)
87+
if (matcherExpirationDate.find()) matcherExpirationDate.group("expirationDate") else null
88+
} else null
89+
90+
// Only proceed if all required fields are present and non-empty
91+
if (!countryCode.isNullOrEmpty() && !documentNumber.isNullOrEmpty() && !dateOfBirth.isNullOrEmpty() && !expirationDate.isNullOrEmpty() && checkDigitDocumentNumber != null) {
92+
val cleanDocumentNumber = cleanDocumentNumber(documentNumber, checkDigitDocumentNumber)
93+
Log.d(TAG, "cleanDocumentNumber")
94+
if (cleanDocumentNumber != null) {
95+
val mrzInfo = createDummyMrz("ID", countryCode, documentNumber, dateOfBirth, expirationDate)
96+
// Log.d(TAG, "MRZ-TD1: $mrzInfo")
97+
callback.onMRZRead(mrzInfo, timeRequired)
98+
return
99+
}
100+
} else {
101+
if (countryCode.isNullOrEmpty()) Log.d(TAG, "Missing or invalid countryCode")
102+
if (documentNumber.isNullOrEmpty()) Log.d(TAG, "Missing or invalid documentNumber")
103+
if (dateOfBirth.isNullOrEmpty()) Log.d(TAG, "Missing or invalid dateOfBirth")
104+
if (expirationDate.isNullOrEmpty()) Log.d(TAG, "Missing or invalid expirationDate")
105+
if (checkDigitDocumentNumber == null) Log.d(TAG, "Missing or invalid checkDigitDocumentNumber")
106+
}
107+
}
108+
54109
if (matcherTD1Line1.find() && matcherTD1Line2.find()) {
110+
Log.d(TAG, "TD1Line1 and TD1Line2 found")
55111
val documentNumber = matcherTD1Line1.group("documentNumber")
56112
val checkDigitDocumentNumber = matcherTD1Line1.group("checkDigitDocumentNumber").toInt()
57113
val dateOfBirth = matcherTD1Line2.group("dateOfBirth")
@@ -62,7 +118,7 @@ object OcrUtils {
62118
val cleanDocumentNumber = cleanDocumentNumber(documentNumber, checkDigitDocumentNumber)
63119
if (cleanDocumentNumber != null) {
64120
val mrzInfo = createDummyMrz(documentType, issuingState, documentNumber, dateOfBirth, expirationDate)
65-
Log.d(TAG, "MRZ-TD1: $mrzInfo")
121+
Log.d(TAG, "cleanDocumentNumber")
66122
callback.onMRZRead(mrzInfo, timeRequired)
67123
return
68124
}

0 commit comments

Comments
 (0)