四季花海
截至SWIFT 4(Xcode 9),SWIFT标准库提供了在SWIFT字符串范围之间进行转换的方法(Range<String.Index>)和NSString范围(NSRange)。例子:let str = "a?b??c"let r1 = str.range(of: "??")!// String range to NSRange:let n1 = NSRange(r1, in: str)print((str as NSString).
substring(with: n1)) // ??// NSRange back to String range:let r2 = Range(n1, in: str)!print(str[r2]) // ??因此,文本字段委托方法中的文本替换现在可以作为func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
if let oldString = textField.text {
let newString = oldString.replacingCharacters(in: Range(range, in: oldString)!,
with: string)
// ... }
// ...}(SWIFT 3及更早版本的旧答案:)斯威夫特1.2,String.Index有一个初始化器init?(_ utf16Index: UTF16Index, within characters: String)可以用来转换NSRange到Range<String.Index>正确(包括所有表情符号、区域指示符或其他扩展的图形素集群),而不中间转换为NSString:extension String {
func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? {
let from16 = advance(utf16.startIndex, nsRange.location, utf16.endIndex)
let to16 = advance(from16, nsRange.length, utf16.endIndex)
if let from = String.Index(from16, within: self),
let to = String.Index(to16, within: self) {
return from ..< to }
return nil
}}此方法返回任选字符串范围,因为不是所有NSRangeS对给定的SWIFT字符串有效。这个UITextFieldDelegate然后,可以将委托方法编写为func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if let swRange = textField.text.rangeFromNSRange(range) {
let newString = textField.text.stringByReplacingCharactersInRange(swRange, withString: string)
// ... }
return true}逆变换是extension String {
func NSRangeFromRange(range : Range<String.Index>) -> NSRange {
let utf16view = self.utf16
let from = String.UTF16View.Index(range.startIndex, within: utf16view)
let to = String.UTF16View.Index(range.endIndex, within: utf16view)
return NSMakeRange(from - utf16view.startIndex, to - from)
}}一个简单的测试:let str = "a?b??c"let r1 = str.rangeOfString("??")!// String range to NSRange:let n1 = str.NSRangeFromRange(r1)println((str as NSString)
.substringWithRange(n1)) // ??// NSRange back to String range:let r2 = str.rangeFromNSRange(n1)!println(str.substringWithRange(r2)) // ??SWIFT 2更新:SWIFT 2版rangeFromNSRange()已经由Serhii Yakovenko在这个答案,我把它包括在这里是为了完整:extension String {
func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? {
let from16 = utf16.startIndex.advancedBy(nsRange.location, limit: utf16.endIndex)
let to16 = from16.advancedBy(nsRange.length, limit: utf16.endIndex)
if let from = String.Index(from16, within: self),
let to = String.Index(to16, within: self) {
return from ..< to }
return nil
}}SWIFT 2版NSRangeFromRange()是extension String {
func NSRangeFromRange(range : Range<String.Index>) -> NSRange {
let utf16view = self.utf16
let from = String.UTF16View.Index(range.startIndex, within: utf16view)
let to = String.UTF16View.Index(range.endIndex, within: utf16view)
return NSMakeRange(utf16view.startIndex.distanceTo(from), from.distanceTo(to))
}}SWIFT 3更新(Xcode 8):extension String {
func nsRange(from range: Range<String.Index>) -> NSRange {
let from = range.lowerBound.samePosition(in: utf16)
let to = range.upperBound.samePosition(in: utf16)
return NSRange(location: utf16.distance(from: utf16.startIndex, to: from),
length: utf16.distance(from: from, to: to))
}}extension String {
func range(from nsRange: NSRange) -> Range<String.Index>? {
guard
let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex),
let to16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location + nsRange.length, limitedBy: utf16.endIndex),
let from = from16.samePosition(in: self),
let to = to16.samePosition(in: self)
else { return nil }
return from ..< to }}例子:let str = "a?b??c"let r1 = str.range(of: "??")!// String range to NSRange:let n1 = str.nsRange(from: r1)print((str as NSString)
.substring(with: n1)) // ??// NSRange back to String range:let r2 = str.range(from: n1)!print(str.substring(with: r2)) // ??