У нас уже есть предложение сначала разбить строку на каждую запятую, а затем разбить каждую часть на знак равенства.Это довольно просто кодировать и работает хорошо, но это не очень эффективно, так как каждый символ должен проверяться несколько раз.Написание правильного парсера с использованием Scanner
так же просто, но будет работать быстрее.
По сути, сканер может проверить, находится ли заданная строка в текущей позиции, или выдать вам подстроку до следующего появления разделителя.
При этом алгоритм будет иметь следующие шаги:
- Создать сканер со строкой ввода
- Проверить открывающую скобку, в противном случае произойдет сбой
- Сканирование до первого
=
.Это ключ - Использовать
=
- Сканирование до первого
,
или ]
.Это значение - Сохраните пару ключ / значение
- Если есть
,
, используйте его и продолжайте с шага 3 - Потребьте окончательный
]
.
К сожалению, API Scanner
не очень удобен для Swift.С небольшим расширением его гораздо проще использовать:
extension Scanner {
func scanString(_ string: String) -> Bool {
return scanString(string, into: nil)
}
func scanUpTo(_ delimiter: String) -> String? {
var result: NSString? = nil
guard scanUpTo(delimiter, into: &result) else { return nil }
return result as String?
}
func scanUpTo(_ characters: CharacterSet) -> String? {
var result: NSString? = nil
guard scanUpToCharacters(from: characters, into: &result) else { return nil }
return result as String?
}
}
С этим мы можем написать функцию разбора следующим образом:
func parse(_ list: String) -> [String: String]? {
let scanner = Scanner(string: list)
guard scanner.scanString("[") else { return nil }
var result: [String: String] = [:]
let endOfPair: CharacterSet = [",", "]"]
repeat {
guard
let key = scanner.scanUpTo("="),
scanner.scanString("="),
let value = scanner.scanUpTo(endOfPair)
else {
return nil
}
result[key] = value
} while scanner.scanString(",")
guard scanner.scanString("]") else { return nil }
return result
}