How can I replace specific characters in UITextView - ios

Hi in the log window I have two array.First one is my colored one as you can see the simulator blue ones.I want to change/replace blue ones with the second array but they are my chords .
Actually I tried like in following codes but all blue text changed with "Dbm" that was the second array's first string.
for txt in coloredTexts {
for transposed in transposedAkorArray{
self.akor_goster.text = self.akor_goster.text.replacingOccurrences(of: "\(txt)", with: "\(transposed)")
}
}

Try,
for (index,txt) in coloredTexts.enumerated() {
let range = akor_goster.text.range(of: txt)
akor_goster.text.replacingOccurrences(of: txt, with: transposedAkorArray[index], options: [], range: range)
}

I think you are trying to do something like this:
for i in 0..<coloredTexts.count {
self.akor_goster.text = self.akor_goster.text.replacingOccurrences(of: "\(coloredTexts[i])", with: "\(transposedAkorArray[i])")
}

Related

Swift 3 : How do you wrap content in a tableviewcell with multiple labels?

I've been trying to figure this out for a while. I have set constraints for each label with background color set. I set each label's line break to word wrap, but that still doesn't work. What I'm looking for is a label wrap like word wrap whether or not that exists. Thanks.
Here is a slightly different approach. You can customize the appearance of each tagged word with an attributed string. This has some limitations but depending on your requirements it could be a good fit for you. The below code is an example pointing you in the correct direction, however you still might need to write additional code for correctly wrapping the spaces or recognizing touch events.
let tags = ["Outdoors", "Working", "Learning"].map { " \($0) " }
let text = tags.joined(separator: " ")
let ranges = tags.compactMap { text.range(of: $0) }
let attributedText = NSMutableAttributedString(string: text)
for range in ranges {
attributedText.addAttributes([.backgroundColor: UIColor.green], range: NSRange(range, in: text))
}
textView.attributedText = attributedText

Swift how to add background color just around text in a label?

How do you add a background color around each variable inside the interests variable? Just around text not the spaces.
var interests = "\(int01) \(int02) \(int03) \(int04) \(int05) \(int06)"
I want it to look like this:
You can use a regex to find anything but white spaces, use a while loop to find its occurrences in a string and use those ranges to change the background color of an attributed string:
Swift 4
let mutable = NSMutableAttributedString(string: interests)
var startIndex = interests.startIndex
while let range = interests.range(of: "\\S+", options: .regularExpression, range: startIndex..<interests.endIndex) {
mutable.addAttribute(.backgroundColor, value: UIColor.cyan, range: NSRange(range, in: interests))
startIndex = range.upperBound
}
label.attributedText = mutable
Note: If you would like to add space around your text you can change your regex to " \\S+ " and don't forget to add spaces at the begin and at the end of your original interests string.
let attributedString = NSMutableAttributedString(string: interests)
attributedString.addAttribute(NSBackgroundColorAttributeName, value: yourColor, range: NSMakeRange(startOfWord, lengthOfWord))
What you can do is use a UICollectionView with cells that have labels that span the entire cell. Each cell then corresponds to individual words. That way you can set either the label or the cell background color to whatever you want.
For ease of implementation, I would turn your interests variable into an array of strings. That way you can easily count the number of cells you need and give each cell the right string.

Scroll down to, **and a little bit past**, a desired spot in a UITextView

What I have:
Working code that scrolls to and highlights the next instance of a search term in a UITextView that contains a moderately lengthy document.
What I want:
Instead of scrolling to the desired term so that it is at the very bottom of the TextView, I'd like to scroll slightly PAST the term so that it is better visible in the view.
Where I'm stuck:
I'm weak on how Swift generally & Swift 4 in particular work with Range, and NSRange, so while I suspect that the answer will include capturing some amount of the document beyond the search term itself (say, the lesser of the next 200 characters or the next 5 line breaks), I'm not clear how to accomplish that. Or if there is a better approach to scroll the view a bit more.
Code #1 -- does the highlighting and finds "this" instance of the search term:
func attributedTextHighlighting(instanceNbr: Int, searchTerm: String, inRawHaystackText: String) -> NSMutableAttributedString {
let desiredFont = UIFont(name: "Menlo-Regular", size: self.currentDisplayFontSize)
let fontAttribute : [NSAttributedStringKey : Any] = [NSAttributedStringKey.font: desiredFont as Any]
let attributed = NSMutableAttributedString(string: inRawHaystackText, attributes: fontAttribute)
if !searchTerm.isEmpty {
do {
let foo = NSRegularExpression.escapedPattern(for: searchTerm)
let regex = try NSRegularExpression(pattern: foo, options: .caseInsensitive)
var countingMatches = 0
for match in regex.matches(in: inRawHaystackText, range: NSRange(location: 0, length:
inRawHaystackText.utf16.count)) as [NSTextCheckingResult] {
if countingMatches == instanceNbr {
// highlight this term green
attributed.addAttribute(NSAttributedStringKey.backgroundColor, value: UIColor.green, range: match.range)
theGreenMatchingRange = match.range
} else {
// highlight this term yellow
attributed.addAttribute(NSAttributedStringKey.backgroundColor, value: UIColor.yellow, range: match.range)
}
// and either way, increment the countingMatches
countingMatches += 1
}
} catch {
fatalError("Bad RegEx! \(error)")
}
} else {
print("ofSearchTerm.isEmpty = true")
}
return attributed
}
This code finds the search term in the source text & generates attributed text that highlights the term green (for the current "find") or yellow (for all others). This code works OK.
Code #2 -- scrolls to the next instance of the search term
func scrollToNextMatchButtonTapped() {
print("scrollToNextMatchButtonTapped")
currentlyHighlightedInstance += 1
if currentlyHighlightedInstance == numberOfInstances {
currentlyHighlightedInstance = 0 // since numberOfInstances is 1-based but currentlyHighlightedInstance is 0-based
}
reloadAttribTextWithHighlighting() // calls the above code, so the green highlight moves to the next found instance
textDisplay.scrollRangeToVisible(theGreenMatchingRange) // would really like to scroll to here plus a few lines (not past the end of the document, obviously)
The last line there works (theGreenMatchingRange is the global variable that's set in Code #1 above to be the range of "this" instance of the search term), but it scrolls so that the green-highlighted term is at the very bottom of the window.
What do I need to add or do differently so that the green term isn't at the very bottom?

Get color changed words of attributed string

I have a UITextView that allows to select words of the text by tapping it. If it is tapped the word is highlighted in color by changing the NSForegroundColor attribute.
Tapping it again deselects it by changing the color back to the textcolor.
Now I would need to know all selected words in the UITextView.
The first idea was to remove everything that is a special character and split the text at space. Then check if the color attribute is equals to the selected/highlighted color of each seperate word.
But attributed string doesn't allow to split at a character or remove components. Neither does NSAttributedString.
Second idea was to save the ranges of the highlighted parts in an array and iterate over it to get the highlighted parts. But this seems a bit too complicated for me, especially as I need the correct order of the words as they appear which is not guaranteed with an array, add/remove on each tap
(For example let's say the text is: "This is a test"
Tap this -> index 0
Tap test -> index 1
Tap this -> test becomes index 0
Tap this -> this becomes index 1
then the order is not good anymore.
I already figured out how to get the color of an attributed string. That's not the problem.
How can I iterate over the attributed string and figure out the words that have changed color or what is the best way to solve this problem?
Thank you!
Greetings
You can iterate over the attributed string looking for the color attribute.
The follow code demonstrates how:
// This generates a test attributed string.
// You actually want the attributedText property of your text view
let str = NSMutableAttributedString(string: "This is a test of the following code")
str.addAttributes([NSForegroundColorAttributeName:UIColor.red], range: NSMakeRange(0, 4))
str.addAttributes([NSForegroundColorAttributeName:UIColor.red], range: NSMakeRange(8, 1))
str.addAttributes([NSForegroundColorAttributeName:UIColor.red], range: NSMakeRange(15, 2))
print(str)
The above prints:
This{
NSColor = "UIExtendedSRGBColorSpace 1 0 0 1";
} is {
}a{
NSColor = "UIExtendedSRGBColorSpace 1 0 0 1";
} test {
}of{
NSColor = "UIExtendedSRGBColorSpace 1 0 0 1";
} the following code{
}
This code processes the attributed string. Any range of text formatted with a foreground color will be put into the words array.
var words = [String]()
str.enumerateAttribute(NSForegroundColorAttributeName, in: NSMakeRange(0, str.length), options: []) { (value, range, stop) in
if value != nil {
let word = str.attributedSubstring(from: range).string
words.append(word)
}
}
print(words)
This prints:
["This", "a", "of"]
I can suggest you to create some kind of storage for selected ranges, then based on this range you can customize look of this words, not the other way. It will allow you to access selected words every time without checking attributes of whole text.
While I agree with Piotr that you should store the Ranges, to answer your question:
attributedString.enumerateAttributes(in: NSMakeRange(0, attributedString.length), options: []) { attributes, range, _ in
if let color = attributes[NSForegroundColorAttributeName] as? UIColor,
color == YOUR_HIGHLIGHT_COLOR {
let nString = attributedString.string as NSString
let word = nString.substring(with: range)
// Do what you want with the word
}
}

How to programmatically enter text in UITextView at the current cursor position

I would like to add (some predefined) text at the current cursor position in a UITextView using Swift. So if I have a UITextField named txtField that has some text in it already such as "this is a beautiful valley" and I tap in the area between "a" and "beautiful" so that the cursor is now in the space between "a" and "beautiful" and then click a Button on my user interface a string of text such as "very" will get typed at the cursor position, so that the text in the UITextView will now become "this is a very beautiful valley". At the end of this operation (after button click event) I would the cursor to be just after the word "very". Many thanks for your help. I can see some question on the forum with similar themes, but the answers are in Objective C. I suicidal like help using Swift.
Try this... Inside your button's IBAction use this (please do not use forced optional unwrapping) or else if the textView has no selection or cursor, the app might crash:
let txt = "whatever you want"
if let range = handleToYourTextView.selectedTextRange {
// From your question I assume that you do not want to replace a selection, only insert some text where the cursor is.
if range.start == range.end {
handleToYourTextView.replaceRange(range, withText: txt)
}
}
try this
textView.replaceRange(textView.selectedTextRange!, withText: "your text")
update:
Swift 5.2
let txt = "whatever you want"
if let range = myTextView.selectedTextRange {
if range.start == range.end {
myTextView.replace(range, withText: txt)
}

Resources