I try to get URLs in text. So, before, I used such an expression:
let re = NSRegularExpression(pattern: "https?:\\/.*", options: nil, error: nil)!
But I had a problem when a user input URLs with Capitalized symbols (like Http://Google.com, it doesn't match it).
I tried:
let re = NSRegularExpression(pattern: "(h|H)(t|T)(t|T)(p|P)s?:\\/.*", options: nil, error: nil)!
But nothing happened.
You turn off case sensitivity using an i inline flag in regex, see Foundation Framework Reference for more information on available regex features.
(?ismwx-ismwx)
Flag settings. Change the flag settings. Changes apply to the portion of the pattern following the setting. For example, (?i) changes to a case insensitive match.The flags are defined in Flag Options.
For readers:
Matching an URL inside larger texts is already a solved problem, but for this case, a simple regex like
(?i)https?://(?:www\\.)?\\S+(?:/|\\b)
will do as OP requires to match only the URLs that start with http or https or HTTPs, etc.
Swift 4
1. Create String extension
import Foundation
extension String {
var isValidURL: Bool {
guard !contains("..") else { return false }
let head = "((http|https)://)?([(w|W)]{3}+\\.)?"
let tail = "\\.+[A-Za-z]{2,3}+(\\.)?+(/(.)*)?"
let urlRegEx = head+"+(.)+"+tail
let urlTest = NSPredicate(format:"SELF MATCHES %#", urlRegEx)
return urlTest.evaluate(with: trimmingCharacters(in: .whitespaces))
}
}
2. Usage
"www.google.com".isValidURL
Try this - http?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?
let pattern = "http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)?"
var matches = [String]()
do {
let regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions(rawValue: 0))
let nsstr = text as NSString
let all = NSRange(location: 0, length: nsstr.length)
regex.enumerateMatchesInString(text, options: NSMatchingOptions.init(rawValue: 0), range: all, usingBlock: { (result, flags, _) in
matches.append(nsstr.substringWithRange(result!.range))
})
} catch {
return [String]()
}
return matches
Make an exension of string
extension String {
var isAlphanumeric: Bool {
return rangeOfString( "^[wW]{3}+.[a-zA-Z]{3,}+.[a-z]{2,}", options: .RegularExpressionSearch) != nil
}
}
call using like this
"www.testsite.edu".isAlphanumeric // true
"flsd.testsite.com".isAlphanumeric //false
My complex solution for Swift 5.x
ViewController:
private func loadUrl(_ urlString: String) {
guard let url = URL(string: urlString) else { return }
let request = URLRequest(url: url)
webView.load(request)
}
UISearchBarDelegate:
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let text = searchBar.text else { return }
if !text.isUrl() {
let finalUrl = String(format: "%#%#", "https://www.google.com/search?q=", text)
loadUrl(finalUrl)
return
}
if text.starts(with: "https://") || text.starts(with: "http://") {
loadUrl(text)
return
}
let finalUrl = String(format: "%#%#", "https://", text)
loadUrl(finalUrl)
}
String extension:
extension String {
func isUrl() -> Bool {
guard !contains("..") else { return false }
let regex = "((http|https)://)?([(w|W)]{3}+\\.)?+(.)+\\.+[A-Za-z]{2,3}+(\\.)?+(/(.)*)?"
let urlTest = NSPredicate(format:"SELF MATCHES %#", regex)
return urlTest.evaluate(with: trimmingCharacters(in: .whitespaces))
}
}
Related
Is it possible to take just a part of the HTML string that I have obtained passing the URL?
Example code below:
let myURLString = "https://myUrl.something"
guard let myURL = NSURL(string: myURLString) else {
print("Error: \(myURLString) doesn't seem to be a valid URL")
return
}
do {
let myHTMLString = try String(contentsOf: myURL as URL)
let htmlString = String(myHTMLString)
print("HTML: \(myHTMLString)")
} catch let error as NSError {
print("Error: \(error)")
}
I want to take what's inside the tag <h3 class="post-title"> to </h3>.
I know that I should use the regular expressions but I don't really know how to set it in the right way. I tried something like this:
let myURLString = "https://www.fvgtech.it/category/podcast/"
guard let myURL = NSURL(string: myURLString) else {
print("Error: \(myURLString) doesn't seem to be a valid URL")
return
}
do {
let myHTMLString = try String(contentsOf: myURL as URL)
let htmlString = String(myHTMLString)
if let match = htmlString.range(of: "(<h3.+)", options: .regularExpression) {
print("Found",htmlString.substring(with: match))
}
print("HTML: \(myHTMLString)")
} catch let error as NSError {
print("Error: \(error)")
}
But it's printing just <h3 class="post-title"> and not what's in the middle. Thanks in advance!
Just we need to search all substrings between start String and end String See Extension of String
let myURLString = "https://www.fvgtech.it/category/podcast/"
guard let myURL = NSURL(string: myURLString) else {
print("Error: \(myURLString) doesn't seem to be a valid URL")
return
}
do {
let myHTMLString = try String(contentsOf: myURL as URL)
let htmlString = String(myHTMLString)
print(htmlString.allStringsBetween("<h3 class=\"post-title\">", andString: "</h3>"))
} catch let error as NSError {
print("Error: \(error)")
}
Extension for String
extension String{
func allStringsBetween(start: String, end: String) -> [Any] {
var strings = [Any]()
var startRange: NSRange = (self as NSString).range(of: start)
while true {
if startRange.location != NSNotFound {
var targetRange = NSRange()
targetRange.location = startRange.location + startRange.length
targetRange.length = self.count - targetRange.location
let endRange: NSRange = (self as NSString).range(of: end, options: [], range: targetRange)
if endRange.location != NSNotFound {
targetRange.length = endRange.location - targetRange.location
strings.append((self as NSString).substring(with: targetRange))
var restOfString = NSRange()
restOfString.location = endRange.location + endRange.length
restOfString.length = self.count - restOfString.location
startRange = (self as NSString).range(of: start, options: [], range: restOfString)
}
else {
break
}
}
else {
break
}
}
return strings
}
}
I have a URL String "http:///blaBla?id=Testid851211" and I just want to get "851211".
Below is my code :-
let url: NSURL = NSURL(string: urlString)!
Helper.sharedInstance.Print(url.query as AnyObject)
if (url.query?.localizedStandardContains("testKey"))! {
//TestKey
Helper.sharedInstance.Print(url.query as AnyObject)
let testValue = getQueryStringParameter(url: urlString, param: "testKey")
Helper.sharedInstance.Print(testValue as AnyObject)
}
else if (url.query?.localizedStandardContains("testID"))! {
//TestID
Helper.sharedInstance.Print(url.query as AnyObject)
}
func getQueryStringParameter(url: String, param: String) -> String? {
guard let url = URLComponents(string: url) else { return nil }
return url.queryItems?.first(where: { $0.name == param })?.value
}
I am getting id = Testid851211 but I want only "851211".
Use a regular expression filtering out numbers only:
let urlString = "http:///blaBla?id=Testid851211"
let pattern = "[0-9]+"
if let matchRange = urlString.range(of: pattern, options: .regularExpression) {
print(urlString[matchRange])
}
Works as long as your URLs don’t have numbers anywhere else.
Try this extension:
extension String {
func getNeededText(for url: String) -> String {
guard range(of: url) != nil else { return "" }
return replacingOccurrences(of: url, with: "")
}
}
Usage:
let predefinedHost = "http:///blaBla?id=Testid"
let url = "http:///blaBla?id=Testid851211"
url.getNeededText(for: predefinedHost) // prints "851211"
I am trying to get the parameters from a URL using Swift. Let's say I have the following URL:
http://mysite3994.com?test1=blah&test2=blahblah
How can I get the values of test1 and test2?
You can use the below code to get the param
func getQueryStringParameter(url: String, param: String) -> String? {
guard let url = URLComponents(string: url) else { return nil }
return url.queryItems?.first(where: { $0.name == param })?.value
}
Call the method like let test1 = getQueryStringParameter(url, param: "test1")
Other method with extension:
extension URL {
public var queryParameters: [String: String]? {
guard
let components = URLComponents(url: self, resolvingAgainstBaseURL: true),
let queryItems = components.queryItems else { return nil }
return queryItems.reduce(into: [String: String]()) { (result, item) in
result[item.name] = item.value
}
}
}
Step 1: Create URL extension
extension URL {
func valueOf(_ queryParameterName: String) -> String? {
guard let url = URLComponents(string: self.absoluteString) else { return nil }
return url.queryItems?.first(where: { $0.name == queryParameterName })?.value
}
}
Step 2: How to use the extension
let newURL = URL(string: "http://mysite3994.com?test1=blah&test2=blahblah")!
newURL.valueOf("test1") // Output i.e "blah"
newURL.valueOf("test2") // Output i.e "blahblah"
I also made a URL extension, but put the query param lookup into a subscript.
extension URL {
subscript(queryParam:String) -> String? {
guard let url = URLComponents(string: self.absoluteString) else { return nil }
return url.queryItems?.first(where: { $0.name == queryParam })?.value
}
}
Usage:
let url = URL(string: "http://some-website.com/documents/127/?referrer=147&mode=open")!
let referrer = url["referrer"] // "147"
let mode = url["mode"] // "open"
It appears that none of existing answers work when the link leads to a web site created on Angular. This is because Angular's paths often include a # (hash) symbol in all links, which results in url.queryItems always returning nil.
If a link looks like this: http://example.com/path/#/morepath/aaa?test1=blah&test2=blahblah
Then the parameters can only be obtained from url.fragment. With some additional parsing logic added to #Matt's extension, a more universal code would look like this:
extension URL {
subscript(queryParam: String) -> String? {
guard let url = URLComponents(string: self.absoluteString) else { return nil }
if let parameters = url.queryItems {
return parameters.first(where: { $0.name == queryParam })?.value
} else if let paramPairs = url.fragment?.components(separatedBy: "?").last?.components(separatedBy: "&") {
for pair in paramPairs where pair.contains(queryParam) {
return pair.components(separatedBy: "=").last
}
return nil
} else {
return nil
}
}
}
Usage remains same:
let url = URL(string: "http://example.com/path/#/morepath/aaa?test1=blah&test2=blahblah")!
let referrer = url["test1"] // "blah"
let mode = url["test2"] // "blahblah"
Another way of doing this is to create an extension on URL to return the components, and then create an extension on [URLQueryItem] to retrieve the value from the queryItems.
extension URL {
var components: URLComponents? {
return URLComponents(url: self, resolvingAgainstBaseURL: false)
}
}
extension Array where Iterator.Element == URLQueryItem {
subscript(_ key: String) -> String? {
return first(where: { $0.name == key })?.value
}
}
And this is an example of how this could be used:
if let urlComponents = URL(string: "http://mysite3994.com?test1=blah&test2=blahblah")?.components,
let test1Value = urlComponents.queryItems?["test1"] {
print(test1Value)
}
I'm trying to run this function when a button is tapped:
#IBAction func openLink(_ sender: UIButton) {
let link1 = "https://www.google.com/#q="
let link2 = birdName.text!
let link3 = link2.replacingOccurrences(of: " ", with: "+") //EDIT
let link4 = link1+link3
guard
let query = link4.addingPercentEncoding( withAllowedCharacters: .urlQueryAllowed),
let url = NSURL(string: "https://google.com/#q=\(query)")
else { return }
UIApplication.shared.openURL(URL(url))
}
However, the last line is flagged as "cannot call value of non-function type "UIApplication". This syntax is from here, so I'm not sure whats going on.
Use guard to unwrap the textfield text property, replacing the occurrences, add percent encoding to the result and create an URL from the resulting string:
Try like this:
guard
let text = birdName.text?.replacingOccurrences(of: " ", with: "+"),
let query = text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: "https://google.com/#q=" + query)
else { return }
if #available(iOS 10.0, *) {
UIApplication.shared.open(url)
} else {
UIApplication.shared.openURL(url)
}
am working on a weather app and i want to generate the image according to the degrees number witch is in a string so how can i extract the number from string
this is the string:
Mostly dry. Very mild (max 19ºC on Sat afternoon, min 15ºC on Sunnight). Wind will be generally light.
#IBAction func weatherButton(sender: UIButton) {
let url = NSURL(string: "http://www.weather-forecast.com/locations/" + cityNameTextField.text.stringByReplacingOccurrencesOfString(" ", withString: "-") + "/forecasts/latest")
if url != nil {
let task = NSURLSession.sharedSession().dataTaskWithURL(url!){ (data, response, error) in
var urlError = false
var weather = ""
if error == nil {
var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding)
var urlContentArray = urlContent!.componentsSeparatedByString("<span class=\"phrase\">")
if urlContentArray.count > 0 {
var weatherArray = urlContentArray[1].componentsSeparatedByString("</span>")
weather = weatherArray[0] as! String
weather = weather.stringByReplacingOccurrencesOfString("°", withString: "º")
println(weather)
}
else {
urlError = true
}
}
else {
urlError = true
}
dispatch_async(dispatch_get_main_queue()) {
if urlError == true {
self.showError()
}
else {
self.weatherFact.text = weather
}
}
}
task.resume()
}
else {
showError()
}
}
Another solution using NSRegularExpression.
The result is an Array of the numbers and the regex considers also temperatures below zero
For Swift 1.2:
let string = "Mostly dry. Very mild (max -19ºC on Sat afternoon, min 15ºC on Sunnight). Wind will be generally light."
let regex = NSRegularExpression(pattern: "-?[0-9]{1,3}", options: NSRegularExpressionOptions(), error: nil)
if let matches = regex?.matchesInString(string, options: NSMatchingOptions(), range: NSRange(location:0, length:count(string))) {
let degrees = matches.map {return (string as NSString).substringWithRange($0.range).toInt()! }
println(degrees) // -> [-19, 15]
}
For Swift 2.0:
let string = "Mostly dry. Very mild (max -19ºC on Sat afternoon, min 15ºC on Sunnight). Wind will be generally light."
do {
let regex = try NSRegularExpression(pattern: "-?[0-9]{1,3}", options: NSRegularExpressionOptions())
let matches = regex.matchesInString(string, options: NSMatchingOptions(), range: NSRange(location: 0, length: string.characters.count))
let degrees = matches.map {Int((string as NSString).substringWithRange($0.range))!}
print(degrees) // -> [-19, 15]
}
catch {
print("NSRegularExpression threw error: \(error)")
}