|
|
import Foundation
|
|
|
|
|
|
// MARK: - 条形码验证器
|
|
|
class BarcodeValidator {
|
|
|
|
|
|
// MARK: - 验证结果
|
|
|
struct ValidationResult {
|
|
|
let isValid: Bool
|
|
|
let formattedContent: String
|
|
|
let errorMessage: String?
|
|
|
let expectedLength: Int?
|
|
|
let allowedCharacters: String?
|
|
|
}
|
|
|
|
|
|
// MARK: - 条形码格式验证规则
|
|
|
static func validateBarcode(_ content: String, type: BarcodeType) -> ValidationResult {
|
|
|
let cleanedContent = content.replacingOccurrences(of: " ", with: "")
|
|
|
|
|
|
switch type {
|
|
|
case .ean13:
|
|
|
return validateEAN13(cleanedContent)
|
|
|
case .ean8:
|
|
|
return validateEAN8(cleanedContent)
|
|
|
case .upce:
|
|
|
return validateUPCE(cleanedContent)
|
|
|
case .code39:
|
|
|
return validateCode39(cleanedContent)
|
|
|
case .code128:
|
|
|
return validateCode128(cleanedContent)
|
|
|
case .itf14:
|
|
|
return validateITF14(cleanedContent)
|
|
|
case .pdf417:
|
|
|
return validatePDF417(cleanedContent)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: - EAN-13 验证
|
|
|
private static func validateEAN13(_ content: String) -> ValidationResult {
|
|
|
// EAN-13: 13位数字
|
|
|
let pattern = "^[0-9]{13}$"
|
|
|
let isValid = content.range(of: pattern, options: .regularExpression) != nil
|
|
|
|
|
|
if isValid {
|
|
|
return ValidationResult(
|
|
|
isValid: true,
|
|
|
formattedContent: formatEAN13(content),
|
|
|
errorMessage: nil,
|
|
|
expectedLength: 13,
|
|
|
allowedCharacters: "numbers_0_9".localized
|
|
|
)
|
|
|
} else {
|
|
|
return ValidationResult(
|
|
|
isValid: false,
|
|
|
formattedContent: content,
|
|
|
errorMessage: "ean_13_must_be_13_digits".localized,
|
|
|
expectedLength: 13,
|
|
|
allowedCharacters: "numbers_0_9".localized
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: - EAN-8 验证
|
|
|
private static func validateEAN8(_ content: String) -> ValidationResult {
|
|
|
// EAN-8: 8位数字
|
|
|
let pattern = "^[0-9]{8}$"
|
|
|
let isValid = content.range(of: pattern, options: .regularExpression) != nil
|
|
|
|
|
|
if isValid {
|
|
|
return ValidationResult(
|
|
|
isValid: true,
|
|
|
formattedContent: formatEAN8(content),
|
|
|
errorMessage: nil,
|
|
|
expectedLength: 8,
|
|
|
allowedCharacters: "numbers_0_9".localized
|
|
|
)
|
|
|
} else {
|
|
|
return ValidationResult(
|
|
|
isValid: false,
|
|
|
formattedContent: content,
|
|
|
errorMessage: "ean_8_must_be_8_digits".localized,
|
|
|
expectedLength: 8,
|
|
|
allowedCharacters: "numbers_0_9".localized
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: - UPC-E 验证
|
|
|
private static func validateUPCE(_ content: String) -> ValidationResult {
|
|
|
// UPC-E: 8位数字
|
|
|
let pattern = "^[0-9]{8}$"
|
|
|
let isValid = content.range(of: pattern, options: .regularExpression) != nil
|
|
|
|
|
|
if isValid {
|
|
|
return ValidationResult(
|
|
|
isValid: true,
|
|
|
formattedContent: formatUPCE(content),
|
|
|
errorMessage: nil,
|
|
|
expectedLength: 8,
|
|
|
allowedCharacters: "numbers_0_9".localized
|
|
|
)
|
|
|
} else {
|
|
|
return ValidationResult(
|
|
|
isValid: false,
|
|
|
formattedContent: content,
|
|
|
errorMessage: "upc_e_must_be_8_digits".localized,
|
|
|
expectedLength: 8,
|
|
|
allowedCharacters: "numbers_0_9".localized
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: - Code 39 验证
|
|
|
private static func validateCode39(_ content: String) -> ValidationResult {
|
|
|
// Code 39: 字母、数字、空格和特殊字符
|
|
|
let pattern = "^[A-Z0-9\\s\\-\\+\\.\\/\\$\\(\\)\\%\\s]+$"
|
|
|
let isValid = content.range(of: pattern, options: .regularExpression) != nil
|
|
|
|
|
|
if isValid {
|
|
|
return ValidationResult(
|
|
|
isValid: true,
|
|
|
formattedContent: formatCode39(content),
|
|
|
errorMessage: nil,
|
|
|
expectedLength: nil,
|
|
|
allowedCharacters: "code_39_characters".localized
|
|
|
)
|
|
|
} else {
|
|
|
return ValidationResult(
|
|
|
isValid: false,
|
|
|
formattedContent: content,
|
|
|
errorMessage: "code_39_only_contains".localized,
|
|
|
expectedLength: nil,
|
|
|
allowedCharacters: "code_39_characters".localized
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: - Code 128 验证
|
|
|
private static func validateCode128(_ content: String) -> ValidationResult {
|
|
|
// Code 128: 支持所有ASCII字符
|
|
|
let pattern = "^[\\x00-\\x7F]+$"
|
|
|
let isValid = content.range(of: pattern, options: .regularExpression) != nil
|
|
|
|
|
|
if isValid {
|
|
|
return ValidationResult(
|
|
|
isValid: true,
|
|
|
formattedContent: formatCode128(content),
|
|
|
errorMessage: nil,
|
|
|
expectedLength: nil,
|
|
|
allowedCharacters: "code_128_characters".localized
|
|
|
)
|
|
|
} else {
|
|
|
return ValidationResult(
|
|
|
isValid: false,
|
|
|
formattedContent: content,
|
|
|
errorMessage: "code_128_only_contains".localized,
|
|
|
expectedLength: nil,
|
|
|
allowedCharacters: "code_128_characters".localized
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: - ITF-14 验证
|
|
|
private static func validateITF14(_ content: String) -> ValidationResult {
|
|
|
// ITF-14: 14位数字
|
|
|
let pattern = "^[0-9]{14}$"
|
|
|
let isValid = content.range(of: pattern, options: .regularExpression) != nil
|
|
|
|
|
|
if isValid {
|
|
|
return ValidationResult(
|
|
|
isValid: true,
|
|
|
formattedContent: formatITF14(content),
|
|
|
errorMessage: nil,
|
|
|
expectedLength: 14,
|
|
|
allowedCharacters: "numbers_0_9".localized
|
|
|
)
|
|
|
} else {
|
|
|
return ValidationResult(
|
|
|
isValid: false,
|
|
|
formattedContent: content,
|
|
|
errorMessage: "itf_14_must_be_14_digits".localized,
|
|
|
expectedLength: 14,
|
|
|
allowedCharacters: "numbers_0_9".localized
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: - PDF417 验证
|
|
|
private static func validatePDF417(_ content: String) -> ValidationResult {
|
|
|
// PDF417: 支持所有ASCII字符
|
|
|
let pattern = "^[\\x00-\\x7F]+$"
|
|
|
let isValid = content.range(of: pattern, options: .regularExpression) != nil
|
|
|
|
|
|
if isValid {
|
|
|
return ValidationResult(
|
|
|
isValid: true,
|
|
|
formattedContent: formatPDF417(content),
|
|
|
errorMessage: nil,
|
|
|
expectedLength: nil,
|
|
|
allowedCharacters: "pdf417_characters".localized
|
|
|
)
|
|
|
} else {
|
|
|
return ValidationResult(
|
|
|
isValid: false,
|
|
|
formattedContent: content,
|
|
|
errorMessage: "pdf417_only_contains".localized,
|
|
|
expectedLength: nil,
|
|
|
allowedCharacters: "pdf417_characters".localized
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: - 格式化方法
|
|
|
private static func formatEAN13(_ content: String) -> String {
|
|
|
// EAN-13: 添加空格分隔符
|
|
|
let formatted = content.enumerated().map { index, char in
|
|
|
if index == 0 || index == 6 || index == 12 {
|
|
|
return " \(char)"
|
|
|
}
|
|
|
return String(char)
|
|
|
}.joined()
|
|
|
return formatted.trimmingCharacters(in: .whitespaces)
|
|
|
}
|
|
|
|
|
|
private static func formatEAN8(_ content: String) -> String {
|
|
|
// EAN-8: 添加空格分隔符
|
|
|
let formatted = content.enumerated().map { index, char in
|
|
|
if index == 0 || index == 4 {
|
|
|
return " \(char)"
|
|
|
}
|
|
|
return String(char)
|
|
|
}.joined()
|
|
|
return formatted.trimmingCharacters(in: .whitespaces)
|
|
|
}
|
|
|
|
|
|
private static func formatUPCE(_ content: String) -> String {
|
|
|
// UPC-E: 添加空格分隔符
|
|
|
let formatted = content.enumerated().map { index, char in
|
|
|
if index == 0 || index == 4 {
|
|
|
return " \(char)"
|
|
|
}
|
|
|
return String(char)
|
|
|
}.joined()
|
|
|
return formatted.trimmingCharacters(in: .whitespaces)
|
|
|
}
|
|
|
|
|
|
private static func formatCode39(_ content: String) -> String {
|
|
|
// Code 39: 保持原样,但去除多余空格
|
|
|
return content.trimmingCharacters(in: .whitespaces)
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static func formatCode128(_ content: String) -> String {
|
|
|
// Code 128: 保持原样
|
|
|
return content.trimmingCharacters(in: .whitespaces)
|
|
|
}
|
|
|
|
|
|
private static func formatITF14(_ content: String) -> String {
|
|
|
// ITF-14: 添加空格分隔符
|
|
|
let formatted = content.enumerated().map { index, char in
|
|
|
if index == 0 || index == 5 || index == 10 {
|
|
|
return " \(char)"
|
|
|
}
|
|
|
return String(char)
|
|
|
}.joined()
|
|
|
return formatted.trimmingCharacters(in: .whitespaces)
|
|
|
}
|
|
|
|
|
|
private static func formatPDF417(_ content: String) -> String {
|
|
|
// PDF417: 保持原样
|
|
|
return content.trimmingCharacters(in: .whitespaces)
|
|
|
}
|
|
|
} |