Skip to content

Commit

Permalink
Merge pull request #8 from magauran/salangin/fixes
Browse files Browse the repository at this point in the history
Amazing fixes
  • Loading branch information
Roman Mazeev authored Sep 25, 2021
2 parents d3f92ce + 35ccd2c commit 98ef7d4
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 24 deletions.
53 changes: 33 additions & 20 deletions Sources/MRZParser/Private/MRZField/MRZFieldFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import Foundation

struct MRZFieldFormatter {
private static let currentCentennial = Calendar.current.component(.year, from: Date()) / 100
private static let previousCentennial = Self.currentCentennial - 1

private let isOCRCorrectionEnabled: Bool
private let ocrCorrector = OCRCorrector()
private let dateFormatter: DateFormatter = {
Expand Down Expand Up @@ -141,15 +144,17 @@ struct MRZFieldFormatter {
private func birthdate(from string: String) -> Date? {
guard CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: string)),
let parsedYear = Int(string.substring(0, to: 1)) else { return nil }
let currentYear = Calendar.current.component(.year, from: Date()) - 2000
let centennial = (parsedYear > currentYear) ? "19" : "20"
let currentYear = Calendar.current.component(.year, from: Date()) - Self.currentCentennial * 100
let centennial = (parsedYear > currentYear) ? String(Self.previousCentennial) : String(Self.currentCentennial)
return dateFormatter.date(from: centennial + string)
}

private func expiryDate(from string: String) -> Date? {
guard CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: string)),
let parsedYear = Int(string.substring(0, to: 1)) else { return nil }
let centennial = (parsedYear >= 70) ? "19" : "20"
let currentYear = Calendar.current.component(.year, from: Date()) - Self.currentCentennial * 100
let boundaryYear = currentYear + 50
let centennial = parsedYear >= boundaryYear ? String(Self.previousCentennial) : String(Self.currentCentennial)
return dateFormatter.date(from: centennial + string)
}

Expand All @@ -162,25 +167,33 @@ struct MRZFieldFormatter {
return checkDigit == "<" ? rawValue.trimmingFillers.isEmpty : false
}

var total = 0

for (index, character) in rawValue.enumerated() {
guard let unicodeScalar = character.unicodeScalars.first else { return false }
let charValue: Int

if CharacterSet.uppercaseLetters.contains(unicodeScalar) {
charValue = Int(10 + unicodeScalar.value) - 65
} else if CharacterSet.decimalDigits.contains(unicodeScalar), let digit = Int(String(character)) {
charValue = digit
} else if character == "<" {
charValue = 0
} else {
return false
}
return Self.checkDigit(for: rawValue) == numericCheckDigit
}

total += charValue * [7, 3, 1][index % 3]
static func checkDigit(for value: String) -> Int? {
var sum: Int = 0
for (index, character) in value.enumerated() {
guard let number = number(for: character) else { return nil }
let weights = [7, 3, 1]
sum += number * weights[index % 3]
}
return sum % 10
}

return total % 10 == numericCheckDigit
// < A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
// 0 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
private static func number(for character: Character) -> Int? {
guard let unicodeScalar = character.unicodeScalars.first else { return nil }
let number: Int
if CharacterSet.uppercaseLetters.contains(unicodeScalar) {
number = Int(10 + unicodeScalar.value) - 65
} else if CharacterSet.decimalDigits.contains(unicodeScalar), let digit = character.wholeNumberValue {
number = digit
} else if character == "<" {
number = 0
} else {
return nil
}
return number
}
}
3 changes: 2 additions & 1 deletion Sources/MRZParser/Private/OCRCorrector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

struct OCRCorrector {
func correct(_ string: String, fieldType: MRZFieldType) -> String {
let string = string.uppercased()
switch fieldType {
// TODO: Check correction of dates (month & day)
case .birthdate, .expiryDate, .hash:
Expand All @@ -17,7 +18,7 @@ struct OCRCorrector {
// TODO: Improve correction (take into account "M" & "<" too)
case .sex:
return string.replace("P", with: "F")
default:
case .documentNumber, .personalNumber, .optionalData:
return string
}
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/MRZParser/Public/MRZParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ public struct MRZParser {
private func mrzFormat(from mrzLines: [String]) -> MRZFormat? {
switch mrzLines.count {
case MRZFormat.td2.linesCount, MRZFormat.td3.linesCount:
return [.td2, .td3].first(where: { $0.lineLenth == uniformedLineLength(for: mrzLines) })
return [.td2, .td3].first(where: { $0.lineLength == uniformedLineLength(for: mrzLines) })
case MRZFormat.td1.linesCount:
return (uniformedLineLength(for: mrzLines) == MRZFormat.td1.lineLenth) ? .td1 : nil
return (uniformedLineLength(for: mrzLines) == MRZFormat.td1.lineLength) ? .td1 : nil
default:
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/MRZParser/Public/MRZResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
public enum MRZFormat: CaseIterable {
case td1, td2, td3

public var lineLenth: Int {
public var lineLength: Int {
switch self {
case .td1:
return 30
Expand Down

0 comments on commit 98ef7d4

Please sign in to comment.