Swift-Rss project-Can't get img src link inside CDATA blocks - regex

I have a very annoying problem. I am developing an RSS Reader for Swift(with Xcode 7.1). i want each cell of my tableview show images for each news. Here is my code:
cell.itemImageView.image = UIImage(named: "placeholder")
let news = items[indexPath.row] as MWFeedItem?
if news?.content != nil {
let htmlContent = news!.content as NSString
var imageSource = ""
let rangeOfString = NSMakeRange(0, htmlContent.length)
let regex = try? NSRegularExpression(pattern: "(<img.*?src=\")(.*?)(\".*?>)", options: [])
if htmlContent.length > 0 {
let match = regex?.firstMatchInString(htmlContent as String, options: [], range: rangeOfString)
if match != nil {
let imageURL = htmlContent.substringWithRange(match!.rangeAtIndex(2)) as NSString
print(imageURL)
if NSString(string: imageURL.lowercaseString).rangeOfString("feedburner").location == NSNotFound {
imageSource = imageURL as String
}
}
}
if imageSource != "" {
cell.itemImageView.setImageWithURL(NSURL(string: imageSource)!, placeholderImage: UIImage(named: "placeholder"))
}
else{
cell.itemImageView.image = UIImage(named: "placeholder")
}
}
So, the problem is that: when the rss feed xml file doesn't have CDATA blocks, my code works perfectly; in other most cases it doesn't work because inside xml file there is a structure like this:
<![CDATA[<p> <img src="http://www.repstatic.it/content/nazionale/img/2015/11/12/115530091-51ce67c2-7b38-41c1-8aa5-21d51b157335.jpg" width="140" align="left" hspace="10">I genitori contro la scelta del consiglio interclasse delle terze elementari dell'istituto Matteotti di fermare la gita all'esposizione "Divina Bellezza" sul...</p>]]></description><guid isPermaLink="true"><!
It's clear that CDATA block doesn't let me read img src link. What can i do?
Thank in advance for your help!

I run the following code in the PlayGround using your regex and successfully got all the img src urls from the xml.
import Foundation
let url = NSURL(string: "http://www.repubblica.it/rss/homepage/rss2.0.xml")!
let xml = try String(contentsOfURL: url)
let regex = try NSRegularExpression(pattern: "(<img.*?src=\")(.*?)(\".*?>)", options: [])
let range = NSMakeRange(0, xml.characters.count)
regex.enumerateMatchesInString(xml, options: [], range: range) { (result, _, _) -> Void in
let nsrange = result!.rangeAtIndex(2)
let start = xml.startIndex.advancedBy(nsrange.location)
let end = start.advancedBy(nsrange.length)
print(xml[start..<end])
}

Related

How to play video with cookies content in iOS using AVPlayer in Swift?

I have used the below implementation to play a video with cookies content from the server, but it shows play icon with cross line. I have refer the link and do following implementation in swift. but I didn't get any output :(
func showVideo(url: String) {
let videoURL = NSURL(string: url)
var cookiesArray = [HTTPCookie]()
guard let cookieArray = UserDefaults.standard.array(forKey:
Constants.Object.kCookie) as? [[HTTPCookiePropertyKey: Any]] else {
return }
for cookieProperties in cookieArray {
if let cookie = HTTPCookie(properties: cookieProperties) {
cookiesArray.append(cookie)
}
}
let cookieArrayOptions = [AVURLAssetHTTPCookiesKey: cookiesArray]
let assets = AVURLAsset(url: videoURL! as URL, options: cookieArrayOptions)
let item = AVPlayerItem(asset: assets)
videoPlayer = AVPlayer(playerItem: item)
self.playerController.player = self.videoPlayer
self.playerController.view.frame = self.view.frame
self.present(self.playerController, animated: true, completion: nil)
self.playerController.player?.play()
}
Please help me on that, what is wrong in that implementation.
Thanks in advance! :)
After going through so many ways finally I have got the solution which worked for me :
func showVideo(url: String) {
let videoURL = NSURL(string: url)
let cookiesArray = HTTPCookieStorage.shared.cookies! //Stored Cookies of your request
let values = HTTPCookie.requestHeaderFields(with: cookiesArray)// Returns a dictionary of header fields corresponding to a provided array of cookies.ex.["Cookie":"your cookies values"]
let cookieArrayOptions = ["AVURLAssetHTTPHeaderFieldsKey": values]
let assets = AVURLAsset(url: videoURL! as URL, options: cookieArrayOptions)
let item = AVPlayerItem(asset: assets)
videoPlayer = AVPlayer(playerItem: item)
self.playerController.player = self.videoPlayer
self.playerController.view.frame = self.view.frame
self.present(self.playerController, animated: true, completion: nil)
self.playerController.player?.play()
}

Writing to text file in swift 3

I am trying to write data that is inputted by a user via UITextField to a text file. I am successfully able to do this by the code I have written below. However, when I tried to save more data it will replace the existing data in the textfile with the new data that is being saved. for example, if I save the string 'hello world' and then save another string saying 'bye'. I will only see the string 'bye' in the textfile. Is there a way I can modify my code so I can see 'hello world' on one line of the textile and 'bye' on another.
#IBAction func btnclicked(_ sender: Any) {
self.savedata(value: answer.text!)
}
func savedata (value: String){
let fileName = "Test"
let DocumentDirURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = DocumentDirURL.appendingPathComponent(fileName).appendingPathExtension("txt")
print("FilePath: \(fileURL.path)")
let writeString = NSString(string: answer.text!)
do {
// Write to the file
try writeString.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8.rawValue)
} catch let error as NSError {
print("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription)
}
}
Here is an example using FIleHandler, adapted to Swift 3, from here (of course you should add all the error handling code that's missing in my example) :
let dir = FileManager.default.urls(for: FileManager.SearchPathDirectory.cachesDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first!
let fileurl = dir.appendingPathComponent("log.txt")
let string = "\(NSDate())\n"
let data = string.data(using: .utf8, allowLossyConversion: false)!
if FileManager.default.fileExists(atPath: fileurl.path) {
if let fileHandle = try? FileHandle(forUpdating: fileurl) {
fileHandle.seekToEndOfFile()
fileHandle.write(data)
fileHandle.closeFile()
}
} else {
try! data.write(to: fileurl, options: Data.WritingOptions.atomic)
}
do {
let fileHandle = try FileHandle(forWritingTo:pathWithFileName)
fileHandle.seekToEndOfFile()
let oldData = try String(contentsOf: pathWithFileName,encoding: .utf8).data(using: .utf8)!
var data = periodValue.data(using: .utf8)!
fileHandle.write(data)
fileHandle.closeFile()
} catch {
print("Error writing to file \(error)")
}
Here is a Swift 4 version as an extension to String.
extension String {
func writeToFile(fileName: String) {
guard let dir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
return
}
let fileUrl = dir.appendingPathComponent(fileName)
guard let data = self.data(using: .utf8) else {
return
}
guard FileManager.default.fileExists(atPath: fileUrl.path) else {
try? data.write(to: fileUrl, options: .atomic)
return
}
if let fileHandle = try? FileHandle(forUpdating: fileUrl) {
fileHandle.seekToEndOfFile()
fileHandle.write(data)
fileHandle.closeFile()
}
}
}

Need help creating a regex pattern for getting an image

I made an RSS reader and I'm trying to get to display a preview image too.
Here's what I'm using to get the image and the only thing that's not working is the pattern
if item?.content != nil {
print("works until here")
let htmlContent = item!.content as NSString
var imageSource = ""
let rangeOfString = NSMakeRange(0, htmlContent.length)
let regex = try! NSRegularExpression(pattern: "(http[^\\s]+(jpg|jpeg|png|tiff)\\b)", options: .caseInsensitive)
if htmlContent.length > 0 {
let match = regex.firstMatch(in: htmlContent as String, options: [], range: rangeOfString)
if match != nil {
let imageURL = htmlContent.substring(with: (match!.rangeAt(2))) as NSString
print(imageURL)
if NSString(string: imageURL.lowercased).range(of: "feedburner").location == NSNotFound {
imageSource = imageURL as String
}
}
}
if imageSource != "" {
cell.itemImageView.setImageWith(NSURL(string: imageSource) as URL!, placeholderImage: UIImage(named: "thumbnail"))
}else {
cell.itemImageView.image = UIImage(named: "thumbnail")
}
}
I need help creating a good pattern for getting the image from "st-gallery" class of the travelator.ro website.
Many thanks in advance. :)
Regular expressions can't parse HTML. Regular expressions recognize the set of Regular Languages. HTML is a context-free language, which is higher on the Chomsky Hierarchy. Regular expressions can't recognize context free languages.
You would need to use a more complicated parser. HTML parsing libraries have done this, I suggest you look at using one of those.

allow only letters for User Name

I'm trying to limit the users First_Name to allow only letters so it should respond with an error for numbers or special characters after clicking on send_button. I found some examples here but because they are build on older swift version I'm having problems to make it work. Until now I've managed to read the First Name and throw an error if the first element on this textfield is not a letter but the code allow things like this (First name = "J123g") or ("Mark##$") and I don't want this to be the case.
func isOneLetter(in text: String) -> Bool {
do {
let regex = try NSRegularExpression(pattern: "[a-zA-Z]")
let nsString = text as NSString
let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
let temp = results.map { nsString.substring(with: $0.range)}
return temp.isEmpty
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return false
}
}
#IBAction func Send_Button(_ sender: AnyObject) {
let UserName = First_Name.text
if (isOneLetter(in: UserName!))
{
DisplayMyAlertMessage(userMessage: "First Name must contain only letter and spaces")
}
}
Your regex pattern checks for one alphanumeric character which matches both unwanted examples.
This regex checks for from beginning (^) to the end ($) of the string there must be one or more (+) alphanumeric characters ([a-zA-Z]). The benefit is that it treats an empty string also as bad.
^[a-zA-Z]+$
1st you have to inherit the UITextViewDelegate class with you own
class
class ViewController: UIViewController, UITextViewDelegate {
2nd add an IBOutlet
#IBOutlet weak var firstName: UITextField!
3rd you have to assure this object is using
override func viewDidLoad() {
super.viewDidLoad()
firstName.delegate = self
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == firstName {
let allowedCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
let allowedCharacterSet = CharacterSet(charactersIn: allowedCharacters)
let typedCharacterSet = CharacterSet(charactersIn: string)
let alphabet = allowedCharacterSet.isSuperset(of: typedCharacterSet)
return alphabet
}
}
Another way could be:
let userInput = ""
let set = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLKMNOPQRSTUVWXYZ")
if userInput.rangeOfCharacter(from: set.inverted) != nil {
print("ERROR: There are numbers included!")
}
Updated for swift 3:
if you want to validate name and allow only letters for User Name then used below simple lines of code :
// function definition:
func isValidName(_ nameString: String) -> Bool {
var returnValue = true
let mobileRegEx = "[A-Za-z]{3}" // {3} -> at least 3 alphabet are compulsory.
do {
let regex = try NSRegularExpression(pattern: mobileRegEx)
let nsString = nameString as NSString
let results = regex.matches(in: nameString, range: NSRange(location: 0, length: nsString.length))
if results.count == 0
{
returnValue = false
}
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
returnValue = false
}
return returnValue
}
// function call :
var firstName = mEnterFirstNameTextField.text!
let isFirstNameValid = isValidName(firstName)
if isFirstNameValid{
// do user logic
}else{
// show error msg: -> "Enter name is not valid, please enter again..."
}

Finding text between parentheses in Swift

How do you get an array of string values for the text between parentheses in Swift?
For example from: MyFileName(2015)(Type)(createdBy).zip
I would like: [2015,Type,createdBy]
Just updating the chosen answer to Swift 3:
func matchesForRegexInText(regex: String!, text: String!) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex, options: [])
let nsString = text as NSString
let results = regex.matches(in: text,
options: [], range: NSMakeRange(0, nsString.length))
return results.map { nsString.substring(with: $0.range)}
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
return []
}}
The usage remains the same.
Here is a complete example in Swift 4.2
func matchesForRegexInText(regex: String!, text: String!) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex, options: [])
let nsString = text as NSString
let results = regex.matches(in: text,
options: [], range: NSMakeRange(0, nsString.length))
return results.map { nsString.substring(with: $0.range)}
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
return []
}}
and usage :
let regex = "\\((.*?)\\)"
mmatchesForRegexInText(regex: regex, text: " exmaple (android) of (qwe123) text (heart) between parentheses")
You can use a regex for this
Thomas had a good example: \((.*?)\)
How to use a regex with Swift you can look up at: http://www.raywenderlich.com/86205/nsregularexpression-swift-tutorial
Here is my RegEx
which is actually trying to get the words between parentheses. E.g. (smile)
NSRegularExpression(pattern: "\\\\(\\\w+\\\\)",options:NSRegularExpressionOptions.CaseInsensitive)
it works for me!