Поиск слова в attributeString из обратного слова и получение диапазона Swift

Как выполнить поиск пробела "" in 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:.
}


}

person PAn Kaj Khatri    schedule 15.08.2015    source источник
comment
Ваш вопрос и код, похоже, мало похожи. Можете ли вы объяснить, что вы хотите, с примером и объяснением, почему вы этого хотите?   -  person Wain    schedule 15.08.2015


Ответы (1)


Отредактированная версия (после обновления вопроса)

Один из способов получить диапазон конечных пробелов для записи расширения String.

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. Обращение строки и получение индекса пробела перед вычитанием этого индекса из длины конечного индекса строки также может оптимизировать ситуацию.

Примечание: код написан на Swift 2 (Xcode 7 beta 5)

person sketchyTech    schedule 15.08.2015
comment
На самом деле я новичок в Swift, но получаю атрибутивное жало, в котором я отправляю диапазон, поэтому из-за этого диапазона последнее слово сокращается наполовину, а другая часть слова отправляется в следующую атрибутированную строку, например... абзац - это слово, а наш диапазон получает parag в первом атрибутированном жале и начинает следующую атрибутированную строку со словом raph. я хочу, чтобы последнее слово было завершено в первой строке или во второй атрибутированной строке - person PAn Kaj Khatri; 15.08.2015
comment
Я не понимаю, хотите ли вы остановить разрывы слов или выполнить поиск по ним. Используете ли вы комбинацию UITextView, NSTextStorage, NSLayoutManager, NSTextContainer и NSAttributedString для управления потоком текста на страницах? Я предполагаю, что сломанное слово написано через дефис. Если вы хотите остановить это, вы можете управлять расстановкой переносов с помощью hyphenationFactor NSMutableParagraphStyle и NSLayoutManager. Как заявляет Apple: когда коэффициент переноса абзаца равен 0,0, вместо него используется коэффициент переноса менеджера компоновки. Когда оба равны 0.0, перенос отключен. - person sketchyTech; 15.08.2015