2015-04-13 9 views
3

Для вывода в программе базы данных у меня есть определенный текст, в который я вставил метки для выделения полужирным шрифтом или курсивом, а также текст, заменяемый изображениями. Например:Измените текст атрибутивной строки и сохраните атрибуты в Swift

«% Важно%^Все сотрудники к breakroom ^» должен иметь конечный результат, как:

ВажныеВсе сотрудники в breakroom

Я код написанный, чтобы найти текст с «%» знаки вокруг него и «^» знаки, но беда у меня сейчас есть текстовые выходы, такие как:

% Важно%^Все сотрудники к breakroom^

Я хотел бы удалить эти% и ^, сохраняя при этом форматирование строки.

Это код, я использую до тех пор, пока он ломает:

func processText(inString string: String) -> NSAttributedString { 

let pattern = ["(?<=\\^).*?(?=\\^)","(?<=\\%).*?(?=\\%)","\\^", "\\%"] 
let italicsRegex = NSRegularExpression(pattern: pattern[0], options: .allZeros, error: nil) 
let range = NSMakeRange(0, count(string)) 
let italicsMatches = italicsRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult] 

var attributedText = NSMutableAttributedString(string: string) 

for match in italicsMatches! { 
    attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Oblique", size: 14.0)!, range: match.range) 
} 

let boldRegex = NSRegularExpression(pattern: pattern[1], options: .allZeros, error: nil) 
let boldMatches = boldRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult] 

for match in boldMatches! { 
    attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size: 14.0)!, range: match.range) 
} 

let removeItalicsMarksRegex = NSRegularExpression(pattern: pattern[2], options: .allZeros, error: nil) 
let removeItalicsMarksMatches = removeItalicsMarksRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult] 

var numberOfLoops = 0 
for match in removeItalicsMarksMatches! { 

    attributedText.replaceCharactersInRange(match.range, withString: "") 

} 

return attributedText.copy() as! NSAttributedString 
} 

Это работает для% матча (но только первый символ) и вызывает сбой на символ^сразу.

Любая помощь или консультация с решением этой проблемы будут оценены. Благодарю.

ответ

2

Martin,

я в конечном итоге использовать что-то очень похожее, но я решил изменить регулярное выражение для включения^метки. При этом я смог затем скопировать первый и последний символы включенной атрибутной подстроки с помощью метода «replaceCharactersInRange». Это пока немного улучшает мои цели, потому что он работает из атрибутной строки, поэтому он не испортит и не удалит какие-либо из его атрибутов.

Я приложил регулярное выражение и часть кода, которая посвящена курсиву для будущей ссылки для кого-то (и спасибо, снова!):

func processText(inString string: String) -> NSAttributedString { 

let pattern = ["\\^.*?\\^"] //Presented as an array here because in the full code there are a lot of patterns that are run. 




let italicsRegex = NSRegularExpression(pattern: pattern[0], options: .allZeros, error: nil) 

//In addition to building the match for this first regular expression, I also gather build the regular expressions and gather matches for all other matching patterns on the initial string ("string") before I start doing any processing. 

    let range = NSMakeRange(0, count(string.utf16)) 

let italicsMatches = italicsRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult] 

var attributedText = NSMutableAttributedString(string: string) 

var charactersRemovedFromString = 0 

for match in italicsMatches! { 

    let newRange = NSMakeRange(match.range.location - charactersRemovedFromString, match.range.length) // Take the updated range for when this loop iterates, otherwise this crashes. 
    attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Oblique", size: 12.0)!, range: newRange) 

    let rangeOfFirstCharacter = NSMakeRange(match.range.location - charactersRemovedFromString, 1) 

    attributedText.replaceCharactersInRange(rangeOfFirstCharacter, withString: "") 

    charactersRemovedFromString += 2 

    let rangeOfLastCharacter = NSMakeRange(match.range.location + match.range.length - charactersRemovedFromString, 1) 

    attributedText.replaceCharactersInRange(rangeOfLastCharacter, withString: "") 
    } 

return attributedText 
} 
1

Это возможное решение, по существу, перевод how to catch multiple instances special indicated **characters** in an NSString and bold them in between? от Objective-C до Swift.

Идея состоит в том, чтобы добавить атрибуты и удалить разделители в одном цикле. Переменная shift необходима для настройки диапазонов соответствия после удаления первых разделителей.

Для простоты показана только обработка «^ ... ^».

func processText(inString string: String) -> NSAttributedString { 

    let pattern = "(\\^)(.*?)(\\^)" 

    let regex = NSRegularExpression(pattern: pattern, options: nil, error: nil)! 
    var shift = 0 // number of characters removed so far 
    let attributedText = NSMutableAttributedString(string: string) 
    regex.enumerateMatchesInString(string, options: nil, range: NSMakeRange(0, count(string.utf16))) { 
     (result, _, _) -> Void in 
     var r1 = result.rangeAtIndex(1) // Location of the leading delimiter 
     var r2 = result.rangeAtIndex(2) // Location of the string between the delimiters 
     var r3 = result.rangeAtIndex(3) // Location of the trailing delimiter 
     // Adjust locations according to the string modifications: 
     r1.location -= shift 
     r2.location -= shift 
     r3.location -= shift 
     // Set attribute for string between delimiters: 
     attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Oblique", size: 14.0)!, range: r2) 
     // Remove leading and trailing delimiters: 
     attributedText.mutableString.deleteCharactersInRange(r3) 
     attributedText.mutableString.deleteCharactersInRange(r1) 
     // Update offset: 
     shift += r1.length + r3.length 
    } 

    return attributedText.copy() as! NSAttributedString 
} 

Обратите внимание, что enumerateMatchesInString() принимает NSRange, поэтому вы должны вычислить количество UTF-16 символов, а не количество символов Swift.

Пример:

let text = "aaa ^bbb^ eee" 
let attrText = processText(inString: text) 
println(attrText) 

Выход:

 
aaa { 
}bbb{ 
    NSFont = " font-family: \"Helvetica-Oblique\"; font-weight: normal; font-style: italic; font-size: 14.00pt"; 
} eee{ 
} 
+0

Благодарим за помощь. Я попробую это, как только смогу. Я видел некоторые версии obj-c этого, но я просто изучаю Swift, поэтому объективный перевод кода не является чем-то, что я могу сделать сам. –

+0

Это очень странно, но в половине случаев этот код возвращает «Выполнение было прервано, причина: EXC_BAD_ACCESS (code = 1 ...)» и половина времени его работы. Любая причина, почему это может быть настолько неустойчивым? –

+0

@DanM: Нет. У вас есть конкретный пример входной строки, где он сбой? –