I am trying to add empty space in the string but after adding it spaces are not showing and If I check the length of String it shows different spaces are there but spaces are not there in display
below is my code and screenshot of the same.
let apple = "apple"
var arabictext = "بيتزا صغيرة بالجبنة"
// here space works
let ababictextWithSpace = "\(apple) \(arabictext)"
print(ababictextWithSpace)
// here space not work
var ababictextWithSpace2 = " \(arabictext) "
print(arabictext)
let str = String(data: arabictext.data(using: .utf8)!, encoding: .utf8)
print("\(str!)".count)
print(" \(str!)".count)
Screenshot with output.
you can try wrapping your string with (""")
Maybe it's console's bug.
In fact they're different, the thing that's different size just proof that.
Related
UILabel.text is not updated inside the main thread. labelOne is updated but labelTwo which is to show translated word is not updated. When I print translatedWord it prints right string to console but UILabel is not updated.
datatask = session.dataTask(with: request, completionHandler: {data, response, error in
if error == nil {
let receivedData = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
DispatchQueue.main.async {
self.labelOne.text = wordTobeTranslated
let data = "\(String(describing: receivedData!["text"]))"
let all = data.components(separatedBy: "(")
let afterAll = all[2]
let last = afterAll.components(separatedBy:")" )
self.translatedWord = last[0]
self.importantWords.append(last[0])
self.labelTwo.text = self.translatedWord
print(self.translatedWord)
}
}
})
datatask?.resume()
Some tips to debug your issue:
Try to set some hard coded string to labelTwo and check whether it
is displaying. (or)
Update any value for labelTwo in Storyboard and check whether is is
displaying.
If string is displayed from any of the above steps, then labelTwo is configured correctly in storyboard.
You can also try self.labelTwo.layoutIfNeeded() method after updating the text to force update the UI.
If none of the steps helps you, check the Font color of UILabel. If it is same as background color, it would not be seen.
Looking at your code sample, it would appear that you’re trying to retrieve:
describing: receivedData!["text"]
from:
\(String(describing: receivedData!["text"]))
The problem is that the \(...) in a String literal results in string interpolation where the expression inside \( and ) will be evaluated and that’s what will be place in the string. And the String(describing: ...) will interpret the value and return a string representation. So, let’s say that receivedData!["text"] contained the word “Foo”. Then
let data = "\(String(describing: receivedData!["text"]))"
Would result in data containing the string, Optional("Foo").
If you want to remove that Optional(...) part, you should either unwrap the optional or use a nil-coalescing operator, ??. And frankly, rather than using string interpolation at all, I’d just do:
let data = String(describing: receivedData?["text"] ?? "")
I know this is an old question, but for new searchers: Try setting number of lines of UILabel to Zero. It might be a constraints issue.
In my iOS/swift project I am loading a RTF document to a UITextView with the code below. The RTF itself contains styled text like "... blah blah [ABC.png] blah blah [DEF.png] blah..." wich is loaded to the UITextView just fine.
Now, I want to replace all occurrences of [someImage.png] with an actual image as NSTextAttachment. How can I do that?
I am aware of the possibility to embed images in RTF documents, but I can not do that in this project.
if let rtfPath = Bundle.main.url(forResource: "testABC", withExtension: "rtf")
{
do
{
//load RTF to UITextView
let attributedStringWithRtf = try NSAttributedString(url: rtfPath, options: [.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil)
txtView.attributedText = attributedStringWithRtf
//find all "[ABC.png]" and replace with image
let regPattern = "\\[.*?\\]"
//now...?
}
}
Here is something that you could do.
Note: I'm not a Swift Developper, more an Objective-C one, so there may be some ugly Swift code (the try!, etc.). But it's more for the logic on using NSRegularExpression (which I used in Objective-C since it's shared in CocoaTouch)
So the main line directives:
Find where are the images placeholders.
Create a NSAttributeString/NSTextAttachment from it.
Replace the placeholder with the previous attributed string.
let regPattern = "\\[((.*?).png)\\]"
let regex = try! NSRegularExpression.init(pattern: regPattern, options: [])
let matches = regex.matches(in: attributedStringWithRtf.string, options: [], range: NSMakeRange(0, attributedStringWithRtf.length))
for aMatch in matches.reversed()
{
let allRangeToReplace = attributedStringWithRtf.attributedSubstring(from: aMatch.range(at: 0)).string
let imageNameWithExtension = attributedStringWithRtf.attributedSubstring(from: aMatch.range(at: 1)).string
let imageNameWithoutExtension = attributedStringWithRtf.attributedSubstring(from: aMatch.range(at: 2)).string
print("allRangeToReplace: \(allRangeToReplace)")
print("imageNameWithExtension: \(imageNameWithExtension)")
print("imageNameWithoutExtension: \(imageNameWithoutExtension)")
//Create your NSAttributedString with NSTextAttachment here
let myImageAttribute = ...
attributedStringWithRtf.replaceCharacters(in: imageNameRange, with: myImageAttributeString)
}
So what's the idea?
I used a modify pattern. I hard-wrote "png", but you could change it. I added some () to get easily the interesting parts. I thought that you may wanted to retrieve the name of the image, with or without the .png, that's why I got all theses print(). Maybe because you saved it in your app, etc. If you need to add the extension as a group, you may want to add it into parenthesis in your regPattern and check what aMatch.range(at: ??) to call. for using Bundle.main.url(forResource: imageName, withExtension: imageExtension)
I used the matches.reversed() because if you modify the length of the "match" with a replacement of different length, the previous ranges will be off. So starting from the end could do the trick.
Some code to transform a UIImage into NSAttributedString through NSTextAttachment: How to add images as text attachment in Swift using nsattributedstring
I'm creating a reading list app, and I'd like to pass the read time of a user added link to a table cell in their reading list - and the only way to get that number is from that page's word count. I've found a few solutions, namely Parsehub, Parse and Mercury but they seem to be geared more towards use cases that need more advanced things to be scraped from a url. Is there a simpler way in Swift to calculate word count of a url?
First of all, you need to parse the HTML. HTML can only be parsed reliably with dedicated HTML parser. Please don't use Regular Expressions or any other search method to parse HTML. You may read it why from this link. If you are using swift, you may try Fuzi or Kanna. After you get the body text with any one of the library, you have to remove extra white spaces and count the words. I have written some basic code with Fuzi library for you to get started.
import Fuzi
// Trim
func trim(src:String) -> String {
return src.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
// Remove Extra double spaces and new lines
func clean(src:String) ->String {
return src.replacingOccurrences(
of: "\\s+",
with: " ",
options: .regularExpression)
}
let htmlUrl = URL(fileURLWithPath: ((#file as NSString).deletingLastPathComponent as NSString).appendingPathComponent("test.html"))
do {
let data = try Data(contentsOf: htmlUrl)
let document = try HTMLDocument(data: data)
// get body of text
if let body = document.xpath("//body").first?.stringValue {
let cleanBody = clean(src: body)
let trimmedBody = trim(src:cleanBody)
print(trimmedBody.components(separatedBy: " ").count)
}
} catch {
print(error)
}
If you are fancy, you may change my global functions to String extension or you can combine them in a single function. I wrote it for clarity.
I'm working with AEXML to write and read xml documents in Swift. I have the writing working no problem. And I have everything setup for the reading, but I can't seem to turn the saved text xml into the document object. It only ever gets the first element and none of the children. I've tried removing all the lines and spaces but still nothing. The content is reading into the String just fine and I've tried converting the data back to a string and it isn't getting messed up in conversion. Is this even possible with AEXML or am I just doing it wrong?
let doc = AEXMLDocument()
let content = try String(contentsOf:NSURL(string:file) as! URL)
let data = content.data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!
let xml = NSString(data:data, encoding:String.Encoding.utf8.rawValue)
try doc.loadXMLData(data)
So I figured out that I was actually using an outdated version of AEXML which clearly wasn't working anymore. The updated code looks like this.
let content = try String(contentsOf:NSURL(string:file) as! URL)
let data = content.data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!
let options = AEXMLOptions()
let doc = try AEXMLDocument(xml:data,options:options)
We're adding the finishing touches to an app we're working on, and that apparently means putting an entire "Terms and Conditions" and "FAQs" section, formatting, bullets, breaks and all.
So I tried copy-pasting it into a textView with "editable" set to off, which kept the bullets, but not the bolded text.
Now, I've done attributed string before, and I have to say, I'm not sure it will be easy to do that on some 12-pages worth of paragraphs, bulleted lists and breaks that are likely to change in a few years or so.
So my question is, is there a way to do this without using attributed string?
Barring that, perhaps there's a way to loop through the text, and look for a written tag that will apply the attributes?
EDIT:
Update. It's been suggested I use HTML tags, and web view. That's what was done for the FAQs (which uses a label), I neglected to mention I tried that too.
For some reason, it just shows a blank textview, albeit a large-sized one, as if there's text in it (there isn't any). Strange that copy-pasting works but this doesn't.
Here's my code for it:
override func awakeFromNib() {
super.awakeFromNib()
termsTitle.text = "Terms and Conditions"
htmlContent = "<p style=\"font-family:Helvetica Neue\"><br/><strong><br/> BLA BLA BLA BLA BLA BLA x 12 Pages"
do {
let str = try NSAttributedString(data: htmlContent.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)!, options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
termsTextView.attributedText = str
} catch {
print("Dim background error")
}
}
I'm pretty sure you can't do this in a Textview without using AttributedString. A possible solution would be using a WebView. Converting your "Terms and Conditions" and "FAQ" to HTML would probably be much easier than using an AttributedString.
If you still want to use your HTML in a UITextView you can try this function:
func getAttributedString(fileName: String) -> NSAttributedString? {
if let htmlLocation = NSBundle.mainBundle().URLForResource(fileName, withExtension: "html"), data = NSData(contentsOfURL: htmlLocation) {
do {
let attrString = try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType], documentAttributes: nil)
return attrString
} catch let err as NSError {
print("Attributed String Creation Error")
print(err.localizedDescription)
return nil
}
} else {
return nil
}
}
This function assumes you have a .html file in your main bundle. You pass it the name (minus extension) of the file (that should be in your project) and then use it like so:
textView.attributedText = getAttributedString("TermsAndConditions")
Just to clarify, the textView is a #IBOutlet on a View Controller in this example.
This function returns nil if either the .html file does not exist or the NSAttributedString conversion failed.