Недавно я столкнулся с проблемой, которая вызвала у меня недоумение. Две одинаковые строки отличались друг от друга. Как такое может быть?
Рассмотрим следующий код:
print("String1: '\(string1)'") print("String2: '\(string2)'") print(string1 == string2)
Получаем следующий вывод:
String1: '123456' String2: '123456' false
Что? Я просто читал строки из файла. Я начал сомневаться в реальности. Строки были одинаковыми и в то же время разными.
Я решил попробовать избавиться от странных символов пробела:
let trimmed1 = string1.trimmingCharacters(in: .whitespacesAndNewlines) let trimmed2 = string2.trimmingCharacters(in: .whitespacesAndNewlines) print("String1: '\(trimmed1)'") print("String2: '\(trimmed2)'") print(trimmed1 == trimmed2)
Нет:
String1: '123456' String2: '123456' false
В конце концов я немного покопался во внутренностях и открыл для себя радости невидимого знака порядка байтов \u{FEFF}
.
Мои строки действительно содержали его (хотя, поскольку я читал их из файла, это было неочевидно):
let string1 = "\u{FEFF}123456" let string2 = "123456"
Теперь у меня есть удобное расширение:
extension String { var withoutBOM: String { let bom = "\u{FEFF}" if hasPrefix(bom) { return String(dropFirst(bom.count)) } return self } }
trimmingCharacters(in: .controlCharacters) тоже справляется с этой задачей:
import Foundation let string1 = "\u{FEFF}123456" let string2 = "123456" let trimmed1 = string1.trimmingCharacters(in: .controlCharacters) let trimmed2 = string2.trimmingCharacters(in: .controlCharacters) print("String1: '\(trimmed1)'") print("String2: '\(trimmed2)'") print(trimmed1 == trimmed2)
String1: '123456' String2: '123456' true
Ух ты! Вселенная снова внутренне непротиворечива (я думаю).