I have the RSS page with the html tag like this:
<description>
<![CDATA[
<a href='https://www.24h.com.vn/bong-da/psg-trao-than-dong-mbappe-sieu-luong-bong-chi-kem-messi-real-vo-mong-c48a1112120.html' title='PSG trao thần đồng Mbappe siĂªu lÆ°Æ¡ng bổng: Chỉ kĂ©m Messi, Real vỡ má»™ng'><img width='130' height='100' src='https://image.24h.com.vn/upload/4-2019/images/2019-12-27/1577463916-359-thumbnail.jpg' alt='PSG trao thần đồng Mbappe siĂªu lÆ°Æ¡ng bổng: Chỉ kĂ©m Messi, Real vỡ má»™ng' title='PSG trao thần đồng Mbappe siĂªu lÆ°Æ¡ng bổng: Chỉ kĂ©m Messi, Real vỡ má»™ng' /></a><br />PSG trong ná»— lá»±c giữ chĂ¢n “sĂ¡t thủ†Kylian Mbappe, sẵn sĂ ng tăng lÆ°Æ¡ng khổng lồ - má»™t Ä‘á»™ng thĂ¡i nhằm xua Ä‘uổi Real Madrid.
]]>
</description>
Please help me how can i get the value of src to show the image. I also try Getting img url from RSS feed swift but it doesn't work. Here is my code to get src (the code always run to image = "nil"):
let regex: NSRegularExpression = try! NSRegularExpression(pattern: "<img.*?src=\"([^\"]*)\"", options: .caseInsensitive)
let range = NSMakeRange(0, description.count)
if let textCheck = regex.firstMatch(in: description, options: .withoutAnchoringBounds, range: range) {
let text = (description as NSString).substring(with: textCheck.range(at: 1))
image = text
} else {
image = "nil"
}
Thank for your helping !
You need to change your regex to be able to match single-quotes as well, not just double quotes, since the html string you're trying to parse contains single quotes, not double quotes like the one in the linked Q&A.
let regex: NSRegularExpression = try! NSRegularExpression(pattern: "<img.*?src=[\"\']([^\"\']*)[\"\']", options: .caseInsensitive)
If you are sure you only need to match single quotes, you can simplify the pattern by replacing [\"\'] with \'. Currently, the regex pattern will match both single and double quotes.
Related
I have string like below
<p><strong>I am a strongPerson</strong></p>
I want to covert this string like this
<p><strong>I am a weakPerson</strong></p>
When I try below code
let old = "<p><strong>I am a strongPerson</strong></p>"
let new = old.replacingOccurrences(of: "strong", with: "weak")
print("\(new)")
I am getting output like
<p><weak>I am a weakPerson</weak></p>
But I need output like this
<p><strong>I am a weakPerson</strong></p>
My Condition here is
1.It has to replace only if word does not contain these HTML Tags like "<>".
Help me to get it. Thanks in advance.
You can use a regular expression to avoid the word being in a tag:
let old = "strong <p><strong>I am a strong person</strong></p> strong"
let new = old.replacingOccurrences(of: "strong(?!>)", with: "weak", options: .regularExpression, range: nil)
print(new)
I added some extra uses of the word "strong" to test edge cases.
The trick is the use of (?!>) which basically means to ignore any match that has a > at the end of it. Look at the documentation for NSRegularExpression and find the documentation for the "negative look-ahead assertion".
Output:
weak <p><strong>I am a weak person</strong></p> weak
Try the following:
let myString = "<p><strong>I am a strongPerson</strong></p>"
if let regex = try? NSRegularExpression(pattern: "strong(?!>)") {
let modString = regex.stringByReplacingMatches(in: myString, options: [], range: NSRange(location: 0, length: myString.count), withTemplate: "weak")
print(modString)
}
In a TextView the user can insert text and images, like a notes. To save the whole TextView content in the database (Realm), I replaced the image itself for a pattern "[image]imageName[/image]", so when I load back this data to the TextView, I want to replace back this pattern for the images. I made this function:
let attributedString = NSMutableAttributedString(string: txtNote.text)
let range = NSRange(location: 0, length: attributedString.string.utf16.count)
let regex = NSRegularExpression("[image](.*?)[/image]")
for match in regex.matches(in: attributedString.string, options: [], range: range) {
if let rangeForImageName = Range(match.range(at: 1), in: attributedString.string){
let imageName = String(attributedString.string[rangeForImageName])
if let image = loadImage(named: imageName) {
let attachment = NSTextAttachment()
attachment.image = image
let oldWidth = attachment.image!.size.width;
let scaleFactor = (oldWidth / (txtNote.frame.size.width - 10))
attachment.image = UIImage(cgImage: attachment.image!.cgImage!, scale: scaleFactor, orientation: .up)
let attString = NSAttributedString(attachment: attachment)
txtNote.textStorage.insert(attString, at: txtNote.selectedRange.location)
} else {
print("Image not found")
}
}
}
I also have this extension to avoid a try catch in the function above:
extension NSRegularExpression {
convenience init(_ pattern: String) {
do {
try self.init(pattern: pattern)
} catch {
preconditionFailure("Illegal regular expression: \(pattern).")
}
}
}
The example that I'm running, the content on attributedString:
Like Gorillaz :D
[image]4397ACA6-ADDC-4977-8D67-9FF44F10384A.jpeg[/image]
[image]9BE22CA8-9C6C-4FF9-B46F-D8AF33703061.jpeg[/image]

Etc.{
}
It should be 2 matches, and the image names should be: "4397ACA6-ADDC-4977-8D67-9FF44F10384A.jpeg" and "9BE22CA8-9C6C-4FF9-B46F-D8AF33703061.jpeg".
But my function is returning 14 matches and the image names like: "k", "ll", "", "]4397ACA6-ADDC-4977-8D67-9FF44F10384A.jp", "[", etc.
Any idea abou what I'm doing wrong? I've been research for some error like this unsuccessfully all day long.
The [image] and [/image] form character classes that match single chars, the former matching i, m, a, g or e and the latter also matching /.
If you want to treat a part of a regex as a literal substring, you may "quote" it with \Q...\E operators:
let regex = NSRegularExpression("\\Q[image]\\E(.*?)\\Q[/image]\\E")
If you are sure what you are doing, escape the brackets manually, "\\[image\\](.*?)\\[/image\\]".
See Regular Expression Metacharacters table:
\Q Quotes all following characters until \E.
\E Terminates a \Q ... \E quoted sequence.
"Quotes" means "adds backslashes before the special chars to make them match as literal chars" here.
What would be the best way to change this string:
"gain quickness for 5 seconds. <c=#reminder>(Cooldown: 90s)</c> only after"
into an Attributed String while getting rid of the part in the <> and I want to change the font of (Cooldown: 90s). I know how to change and make NSMutableAttributedStrings but I am stuck on how to locate and change just the (Cooldown: 90s) in this case. The text in between the <c=#reminder> & </c> will change so I need to use those to find what I need.
These seem to be indicators meant to be used for this purpose I just don't know ho.
First things first, you'll need a regular expression to find and replace all tagged strings.
Looking at the string, one possible regex could be <c=#([a-zA-Z-9]+)>([^<]*)</c>. Note that will will work only if the string between the tags doesn't contain the < character.
Now that we have the regex, we only need to apply it on the input string:
let str = "gain quickness for 5 seconds. <c=#reminder>(Cooldown: 90s)</c> only after"
let attrStr = NSMutableAttributedString(string: str)
let regex = try! NSRegularExpression(pattern: "<c=#([a-zA-Z-9]+)>([^<]*)</c>", options: [])
while let match = regex.matches(in: attrStr.string, options: [], range: NSRange(location: 0, length: attrStr.string.utf16.count)).first {
let indicator = str[Range(match.range(at: 1), in: str)!]
let substr = str[Range(match.range(at: 2), in: str)!]
let replacement = NSMutableAttributedString(string: String(substr))
// now based on the indicator variable you might want to apply some transformations in the `substr` attributed string
attrStr.replaceCharacters(in: match.range, with: replacement)
}
I am stuck at getting a string from html body
<html><head>
<title>Uaeexchange Mobile Application</title></head><body>
<div id='ourMessage'>
49.40:51.41:50.41
</div></body></html>
I Would like to get the string containing 49.40:51.41:50.41 . I don't want to do it by string advance or index. Can I get this string by specifying I need only numbers,dot(.) and colon(:) in swift. I mean some numbers and some special characters?
I tried
let stringArray = response.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")
print("Trimmed\(newString)and count\(newString.characters.count)")
but this obviously trims away dot and colon too. any suggestions friends?
The simple answer to your question is that you need to include "." & ":" in the set that you want to keep.
let response: String = "<html><head><title>Uaeexchange Mobile Application</title></head><body><div id='ourMessage'>49.40:51.41:50.41</div></body></html>"
var s: CharacterSet = CharacterSet.decimalDigits
s.insert(charactersIn: ".:")
let stringArray: [String] = response.components(separatedBy: s.inverted)
let newString: String = stringArray.joined(separator: "")
print("Trimmed '\(newString)' and count=\(newString.characters.count)")
// "Trimmed '49.40:51.41:50.41' and count=17\n"
Without more information on what else your response might be, I can't really give a better answer, but fundamentally this is not a good solution. What if the response had been
<html><head><title>Uaeexchange Mobile Application</title></head><body>
<div id='2'>Some other stuff: like this</div>
<div id='ourMessage'>49.40:51.41:50.41</div>
</body></html>
Using a replace/remove solution to this is a hack, not an algorithm - it will work until it doesn't.
I think you should probably be looking for the <div id='ourMessage'> and reading from there to the next <, but again, we'd need more information on the specification of the format of the response.
I'd recommend to use an HTML parser, nevertheless this is a simple solution with regular expression:
let extractedString = response.replacingOccurrences(of: "[^\\d:.]+", with: "", options: .regularExpression)
Or the positive regex search which is more code but also more reliable:
let pattern = ">\\s?([\\d:.]+)\\s?<"
let regex = try! NSRegularExpression(pattern: pattern)
if let match = regex.firstMatch(in: response, range: NSMakeRange(0, response.utf8.count)) {
let range = match.rangeAt(1)
let startIndex = response.index(response.startIndex, offsetBy: range.location)
let endIndex = response.index(startIndex, offsetBy: range.length)
let extractedString = response.substring(with: startIndex..<endIndex)
print(extractedString)
}
While the simple (negative) regex search removes all characters which don't match digits, dots and colons the positive search considers also the closing (>) and opening tags (<) around the desired result so an accidental digit, dot or colon doesn't match the pattern.
You can also use the String.replacingOccurrences() method in other ways, without regex, as follows:
import Foundation
var response: String = "<html><head><title>Uaeexchange Mobile Application</title></head><body><div id='ourMessage'>49.40:51.41:50.41</div></body></html>"
let charsNotToBeTrimmed = (0...9).map{String($0)} + ["." ,":"] // you can add any character you want here, that's the advantage
for i in response.characters{
if !charsNotToBeTrimmed.contains(String(i)){
response = response.replacingOccurrences(of: String(i), with: "")
}
}
print(response)
Basically, this creates an array of characters which should not be trimmed and if a character is not out there, it gets removed in the for-loop
But you have to be warned that what you're trying to do isn't quite right...
I have a HTML file embedded into my xCode project which has tags within it such as:
{DESCRIPTION}
{LOCATION}
{TIME_SUBMITTED}
I load the contents of the file into a String with:
let url = Bundle.main.url(forResource: "emailTemplate", withExtension: "html")
var messageBody:NSString!
do { messageBody = try String(contentsOf: url!) as NSString! }
catch { messageBody = "" }
Now I have populated "messageBody" I need to find and replace the tags based on my UI, for example:
1) find "{DESCRIPTION}" and replace it with lblDescription.text
2) find "{LOCATION}" and replace it with lblLocation.text
I am trying to use code similar to:
messageBody.enumerateSubstrings(in: NSMakeRange(0, messageBody.length), options: .byWords) { (substring, substringRange, enclosingRange, _) -> () in
print(substring!)
}
However, I am completely useless with regex and could do with some assistance to find and replace if the substring equals a tag. Any ideas please?
You don't need regex for this. Repeated calls to replacingOccurrences will do:
import Foundation
let emailTemplate = "Hello {USER}\n" +
"{DESCRIPTION}\n" +
"\n" +
"Regards."
let email = emailTemplate
.replacingOccurrences(of: "{USER}", with: "John Smith")
.replacingOccurrences(of: "{DESCRIPTION}", with: "Have a nice day")
print(email)