Как я могу использовать NSRegularExpression в строках Swift с символами Unicode переменной ширины?

У меня возникли проблемы с получением NSRegularExpression для сопоставления шаблонов в строках с более широкими (?) символами Unicode в них. Похоже, проблема заключается в параметре диапазона — Swift подсчитывает отдельные символы Unicode, в то время как Objective-C обрабатывает строки так, как будто они состоят из кодовых единиц UTF-16.

Вот моя тестовая строка и два регулярных выражения:

let str = "dog????????cow"
let dogRegex = NSRegularExpression(pattern: "d.g", options: nil, error: nil)!
let cowRegex = NSRegularExpression(pattern: "c.w", options: nil, error: nil)!

Я могу сопоставить первое регулярное выражение без проблем:

let dogMatch = dogRegex.firstMatchInString(str, options: nil, 
                   range: NSRange(location: 0, length: countElements(str)))
println(dogMatch?.range)  // (0, 3)

Но второй не работает с теми же параметрами, потому что диапазон, который я ему отправляю (0...7), недостаточно велик, чтобы охватить всю строку, насколько это касается NSRegularExpression:

let cowMatch = cowRegex.firstMatchInString(str, options: nil, 
                   range: NSRange(location: 0, length: countElements(str)))
println(cowMatch.range)  // nil

Если я использую другой диапазон, я могу добиться успеха:

let cowMatch2 = cowRegex.firstMatchInString(str, options: nil, 
                    range: NSRange(location: 0, length: str.utf16Count))
println(cowMatch2?.range)  // (7, 3)

но тогда я не знаю, как извлечь совпадающий текст из строки, поскольку этот диапазон выходит за пределы диапазона строки Swift.


person Nate Cook    schedule 17.09.2014    source источник
comment
+один за ссылку на собачью корову.   -  person devios1    schedule 14.02.2016


Ответы (1)


Оказывается, можно бороться с огнем огнем. Использование свойства utf16Count строки Swift и метода substringWithRange: NSString -- не String -- дает правильный результат. Вот полный рабочий код:

let str = "dog????????cow"
let cowRegex = NSRegularExpression(pattern: "c.w", options: nil, error: nil)!

if let cowMatch = cowRegex.firstMatchInString(str, options: nil,
                      range: NSRange(location: 0, length: str.utf16Count)) {
    println((str as NSString).substringWithRange(cowMatch.range))
    // prints "cow"
}

(Я понял это в процессе написания вопроса; балл за отладку резиновой утки.)

person Nate Cook    schedule 17.09.2014
comment
Если вы сначала конвертируете let nsstr = str as NSString, вы можете просто использовать length: [nsstr length], как в ObjC. - person Martin R; 17.09.2014