NSRegularExpressionやNSDataDetectorで指定するrangeにはString.utf16.countを使う
テキストからリンクを抜き出す場合などよくこういったコードを見ますが、テキストにサロゲートペアが含まれているとマッチの対象がサロゲートペアの分短く解釈され、末尾が切れたりします。
let text = "🍣 is sushi http://example.com/hello" let detector = try! NSDataDetector(types: NSTextCheckingType.Link.rawValue) let matches = detector.matchesInString(text, options: [], range: NSRange.init(location: 0, length: text.characters.count)) for match in matches { let link = (text as NSString).substringWithRange(match.range) print(link) // -> http://example.com/hell }
String.utf16.count を使うと期待した結果を得ることが出来ます。
let text = "🍣 is sushi http://example.com/abc" let detector = try! NSDataDetector(types: NSTextCheckingType.Link.rawValue) let matches = detector.matchesInString(text, options: [], range: NSRange.init(location: 0, length: text.utf16.count)) for match in matches { let link = (text as NSString).substringWithRange(match.range) print(link) // -> http://example.com/hello }
しかしこれは本当に気づきにくくSwiftライブラリでも characters.count を利用している例が多いです。