找到你要的答案

Q:Search word in attributedString from backword and get range Swift

Q:在attributedstring从反向搜索词和范围迅速

How do I search the space "" in anattributedString from the end of the string backwards and then get the range of that space?

I am getting an attributed string form an rtf-file and from this I divide it into multiple attributed strings so I can show those on screen as the pages.

But when I am retrieving the attributed string, for example in the range of 500, the last word of the substring is incomplete.

Below is the AppDelegate class code:

//  AppDelegate.swift

struct ScreenSize
{
static let SCREEN_WIDTH         = UIScreen.mainScreen().bounds.size.width
static let SCREEN_HEIGHT        = UIScreen.mainScreen().bounds.size.height
static let SCREEN_MAX_LENGTH    = max(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
static let SCREEN_MIN_LENGTH    = min(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
}
struct DeviceType
{
static let IS_IPHONE_4_OR_LESS  = UIDevice.currentDevice().userInterfaceIdiom == .Phone && ScreenSize.SCREEN_MAX_LENGTH < 568.0
static let IS_IPHONE_5          = UIDevice.currentDevice().userInterfaceIdiom == .Phone && ScreenSize.SCREEN_MAX_LENGTH == 568.0
static let IS_IPHONE_6          = UIDevice.currentDevice().userInterfaceIdiom == .Phone && ScreenSize.SCREEN_MAX_LENGTH == 667.0
static let IS_IPHONE_6P         = UIDevice.currentDevice().userInterfaceIdiom == .Phone && ScreenSize.SCREEN_MAX_LENGTH == 736.0
static let IS_IPAD              = UIDevice.currentDevice().userInterfaceIdiom == .Pad && ScreenSize.SCREEN_MAX_LENGTH == 1024.0
}
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?
var pageText:[NSAttributedString] = []
var startIndex = 0
var endIndex = 500
var divideFactor = Int()

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    if DeviceType.IS_IPHONE_4_OR_LESS
    {
    endIndex = 700
    }
    else if DeviceType.IS_IPHONE_5
    {
    endIndex = 900
    }
    else if DeviceType.IS_IPHONE_6
    {
    endIndex = 1300
    }
    else if DeviceType.IS_IPHONE_6P
    {
    endIndex = 1700
    }
    else
    {
    endIndex = 2000
    }



    UINavigationBar.appearance().barTintColor = UIColor(red: 144.0/255, green:  14.0/255, blue: 0/255, alpha: 1.0)
    UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor()]
    UIBarButtonItem.appearance().tintColor = UIColor.whiteColor()
    UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)

    for var i=1 ; i<=1 ; i++ {
        if let rtfPath = NSBundle.mainBundle().URLForResource("Quran2", withExtension: "rtf") {
            let attributedStringWithRtf = NSMutableAttributedString(fileURL: rtfPath, options: [NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType], documentAttributes: nil, error: nil)!

            var lengthOfRtf = attributedStringWithRtf.length
            divideFactor = Int(lengthOfRtf/endIndex)
            println(divideFactor)
            self.updateTextFont(attributedStringWithRtf) (valueFactor: divideFactor)

        }
    }

    return true
}
func updateTextFont(mystring:NSMutableAttributedString) (valueFactor:Int) {

    let screenSizeMain: CGRect = UIScreen.mainScreen().bounds
    let myAttriText:NSMutableAttributedString = mystring.mutableCopy() as! NSMutableAttributedString
    myAttriText.beginEditing()
    myAttriText.enumerateAttributesInRange(NSMakeRange(0, myAttriText.length), options: NSAttributedStringEnumerationOptions.Reverse) { (attribute, range, stop) -> Void in

        var mutableAttributes = NSDictionary(dictionary: attribute)
        var font:UIFont = mutableAttributes.objectForKey(NSFontAttributeName) as! UIFont
        var newFont:UIFont = font.fontWithSize(font.pointSize)

        if DeviceType.IS_IPAD
        {
            newFont = font.fontWithSize(font.pointSize+7)

        }
        var fontProperties:UIFontDescriptor = font.fontDescriptor()
        let sizeNumber:Float = fontProperties.fontAttributes()[UIFontDescriptorSizeAttribute] as! Float
        myAttriText.addAttribute(NSFontAttributeName, value: newFont, range: range)

    }

    for var i=0; i < valueFactor; i++ {

        let range =  NSMakeRange(startIndex, endIndex)
        var nsText = myAttriText.attributedSubstringFromRange(range)
        pageText.append(nsText)
        println(endIndex)

    }

    myAttriText.endEditing()

}

func visibleRangeOfTextView(textView: NSAttributedString) -> NSRange {
    return NSMakeRange(startIndex, endIndex)

}

func applicationWillResignActive(application: UIApplication) {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

func applicationDidEnterBackground(application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

func applicationWillEnterForeground(application: UIApplication) {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

func applicationDidBecomeActive(application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

func applicationWillTerminate(application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}


}

我如何搜索空间”在anattributedstring从字符串的末尾,然后向后,空间范围呢?

我得到一个属性的字符串形式的RTF文件,我把它划分为多个属性字符串,所以我可以显示屏幕上的页面。

但当我检索属性的字符串,例如在500的范围内,子串的最后一句话是不完整的。

下面是AppDelegate类代码:

//  AppDelegate.swift

struct ScreenSize
{
static let SCREEN_WIDTH         = UIScreen.mainScreen().bounds.size.width
static let SCREEN_HEIGHT        = UIScreen.mainScreen().bounds.size.height
static let SCREEN_MAX_LENGTH    = max(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
static let SCREEN_MIN_LENGTH    = min(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
}
struct DeviceType
{
static let IS_IPHONE_4_OR_LESS  = UIDevice.currentDevice().userInterfaceIdiom == .Phone && ScreenSize.SCREEN_MAX_LENGTH < 568.0
static let IS_IPHONE_5          = UIDevice.currentDevice().userInterfaceIdiom == .Phone && ScreenSize.SCREEN_MAX_LENGTH == 568.0
static let IS_IPHONE_6          = UIDevice.currentDevice().userInterfaceIdiom == .Phone && ScreenSize.SCREEN_MAX_LENGTH == 667.0
static let IS_IPHONE_6P         = UIDevice.currentDevice().userInterfaceIdiom == .Phone && ScreenSize.SCREEN_MAX_LENGTH == 736.0
static let IS_IPAD              = UIDevice.currentDevice().userInterfaceIdiom == .Pad && ScreenSize.SCREEN_MAX_LENGTH == 1024.0
}
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?
var pageText:[NSAttributedString] = []
var startIndex = 0
var endIndex = 500
var divideFactor = Int()

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    if DeviceType.IS_IPHONE_4_OR_LESS
    {
    endIndex = 700
    }
    else if DeviceType.IS_IPHONE_5
    {
    endIndex = 900
    }
    else if DeviceType.IS_IPHONE_6
    {
    endIndex = 1300
    }
    else if DeviceType.IS_IPHONE_6P
    {
    endIndex = 1700
    }
    else
    {
    endIndex = 2000
    }



    UINavigationBar.appearance().barTintColor = UIColor(red: 144.0/255, green:  14.0/255, blue: 0/255, alpha: 1.0)
    UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor()]
    UIBarButtonItem.appearance().tintColor = UIColor.whiteColor()
    UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)

    for var i=1 ; i<=1 ; i++ {
        if let rtfPath = NSBundle.mainBundle().URLForResource("Quran2", withExtension: "rtf") {
            let attributedStringWithRtf = NSMutableAttributedString(fileURL: rtfPath, options: [NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType], documentAttributes: nil, error: nil)!

            var lengthOfRtf = attributedStringWithRtf.length
            divideFactor = Int(lengthOfRtf/endIndex)
            println(divideFactor)
            self.updateTextFont(attributedStringWithRtf) (valueFactor: divideFactor)

        }
    }

    return true
}
func updateTextFont(mystring:NSMutableAttributedString) (valueFactor:Int) {

    let screenSizeMain: CGRect = UIScreen.mainScreen().bounds
    let myAttriText:NSMutableAttributedString = mystring.mutableCopy() as! NSMutableAttributedString
    myAttriText.beginEditing()
    myAttriText.enumerateAttributesInRange(NSMakeRange(0, myAttriText.length), options: NSAttributedStringEnumerationOptions.Reverse) { (attribute, range, stop) -> Void in

        var mutableAttributes = NSDictionary(dictionary: attribute)
        var font:UIFont = mutableAttributes.objectForKey(NSFontAttributeName) as! UIFont
        var newFont:UIFont = font.fontWithSize(font.pointSize)

        if DeviceType.IS_IPAD
        {
            newFont = font.fontWithSize(font.pointSize+7)

        }
        var fontProperties:UIFontDescriptor = font.fontDescriptor()
        let sizeNumber:Float = fontProperties.fontAttributes()[UIFontDescriptorSizeAttribute] as! Float
        myAttriText.addAttribute(NSFontAttributeName, value: newFont, range: range)

    }

    for var i=0; i < valueFactor; i++ {

        let range =  NSMakeRange(startIndex, endIndex)
        var nsText = myAttriText.attributedSubstringFromRange(range)
        pageText.append(nsText)
        println(endIndex)

    }

    myAttriText.endEditing()

}

func visibleRangeOfTextView(textView: NSAttributedString) -> NSRange {
    return NSMakeRange(startIndex, endIndex)

}

func applicationWillResignActive(application: UIApplication) {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

func applicationDidEnterBackground(application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

func applicationWillEnterForeground(application: UIApplication) {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

func applicationDidBecomeActive(application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

func applicationWillTerminate(application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}


}
answer1: 回答1:

Edited version (following update of question)

One way of obtaining the range of the final spaces to write a String extension.

extension String {

  func getMatches(regex: String, options: NSStringCompareOptions?) -> [Range<String.Index>] {
    var arr = [Range<String.Index>]()
    var rang = Range(start: self.startIndex, end: self.endIndex)
    var foundRange:Range<String.Index>?

    repeat
    {
        foundRange = self.rangeOfString(regex, options: options ?? [], range: rang, locale: nil)

        if let a = foundRange {
            arr.append(a)
            rang.startIndex = foundRange!.endIndex
        }
    }
        while foundRange != nil
    return  arr
   }

}

This can then be implemented as follows:

let attrStr = NSAttributedString(string: "Hello, playground. How are you, today?")
// obtain range of final space
let ranges = attrStr.string.getMatches(" ", options: [])
let rangeOfFinalSpace = ranges[advance(ranges.endIndex, -2, ranges.startIndex)]

Other Approaches

This is a bit of a hurried reply, and the code could be stripped back further. Also worth considering is use of NSCharacterSet for whitespace and newline characters, and/or NSScanner. Reversing the string and getting the index of the whitespace before subtracting that index from the length of the string's final index might also optimise things.

Note: the code is written in Swift 2 (Xcode 7 beta 5)

编辑版本(以下问题更新)

获取最终空格的范围的一种方法,写一个字符串扩展名。

extension String {

  func getMatches(regex: String, options: NSStringCompareOptions?) -> [Range<String.Index>] {
    var arr = [Range<String.Index>]()
    var rang = Range(start: self.startIndex, end: self.endIndex)
    var foundRange:Range<String.Index>?

    repeat
    {
        foundRange = self.rangeOfString(regex, options: options ?? [], range: rang, locale: nil)

        if let a = foundRange {
            arr.append(a)
            rang.startIndex = foundRange!.endIndex
        }
    }
        while foundRange != nil
    return  arr
   }

}

然后可以执行如下:

let attrStr = NSAttributedString(string: "Hello, playground. How are you, today?")
// obtain range of final space
let ranges = attrStr.string.getMatches(" ", options: [])
let rangeOfFinalSpace = ranges[advance(ranges.endIndex, -2, ranges.startIndex)]

其他的方法

这是一个匆忙的答复,代码可以被进一步删除。还值得考虑的是用空格和换行符nscharacterset,和/或NSScanner。反转字符串之前从字符串的长度减去最终的指数,指数也可能优化的事情的空白索引。

注:代码是用快2(Xcode 7 Beta 5)

swift  nsattributedstring  nsrange