StringBetweenString function - ios

I need to get substring between two strings from my text. For example, I have text "http://google.com" and I want to get substring between "://" and ".".
I don't know, how I can do that.
I try to use regular expressions, but I think, it's bad way.

A couple of options:
Regular expressions work well. See ICU User Guide: Regular Expressions
Example:
let us = "http://google.com"
let range = us.rangeOfString("(?<=://)[^.]+(?=.)", options:.RegularExpressionSearch)
if range != nil {
let found = us.substringWithRange(range!)
println("found: \(found)") // found: google
}
Notes:
(?<=://) means preceded by ://
[^.]+ means any characters except .
(?=.) means followed by .
NSScanner is also a good method. See Apple's NSScanner Class Reference
Example:
let us = "http://google.com"
let scanner = NSScanner(string:us)
var scanned: NSString?
if scanner.scanUpToString("://", intoString:nil) {
scanner.scanString("://", intoString:nil)
if scanner.scanUpToString(".", intoString:&scanned) {
let result: String = scanned as String
println("result: \(result)") // result: google
}
}

You can use the regular Expression
://.+.
it matches to
://google.
in this code:
var yourURL: NSString = "http://google.com" // this is your input and could be any URL
var regex: NSRegularExpression = NSRegularExpression.regularExpressionWithPattern("://.+\\.", options: NSRegularExpressionOptions.fromMask(UInt(0)), error: nil) // need double backspace because of backspace in String is \\ not \
var needleRange = regex.rangeOfFirstMatchInString(yourURL, options:NSMatchingOptions.Anchored, range: NSMakeRange(0, yourURL.length))
var needle: NSString = yourURL.substringWithRange(needleRange)
Now you can remove the first 3 symbols and the last one and you got
google
with this code:
import Foundation
var halfURL: NSString = "://google."
var prefix: NSString = "://"
var suffix: NSString = "."
var needleRange: NSRange = NSMakeRange(prefix.length, halfURL.length - prefix.length - suffix.length)
var needle: NSString = halfURL.substringWithRange(needleRange)
// needle is now 'google'

If your input is a valid URL, you can take advantage of the NSURL class to do the parsing for you:
var result : NSString?
let input = "http://test.com/blabla"
// Parse the string; might fail
let url : NSURL? = NSURL(string: input)
// Get the host part of the URL ("test.com")
let host = url?.host
// Split it up at the dots.
let hostParts = host?.componentsSeparatedByString(".")
// Assign the first part of the hostname if we were successful up to here.
if hostParts?.count > 0 {
result = hostParts![0]
}
Bonus: ignore "www":
if hostParts?.count > 0 {
if (hostParts![0] == "www" && hostParts!.count > 1) {
result = hostParts![1]
} else {
result = hostParts![0]
}
}

For swift 3.0:
let us = "http://example.com"
let range = us.range(of:"(?<=://)[^.]+(?=.com)", options:.regularExpression)
if range != nil {
let found = us.substring(with: range!)
print("found: \(found)") // found: example
}

Related

Alamofire returning nil as response for google snap to road api call and shows Alamofire.AFError.invalidURL [duplicate]

If I encode a string like this:
var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
it doesn't escape the slashes /.
I've searched and found this Objective C code:
NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8 );
Is there an easier way to encode an URL and if not, how do I write this in Swift?
Swift 3
In Swift 3 there is addingPercentEncoding
let originalString = "test/test"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(escapedString!)
Output:
test%2Ftest
Swift 1
In iOS 7 and above there is stringByAddingPercentEncodingWithAllowedCharacters
var originalString = "test/test"
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
println("escapedString: \(escapedString)")
Output:
test%2Ftest
The following are useful (inverted) character sets:
URLFragmentAllowedCharacterSet "#%<>[\]^`{|}
URLHostAllowedCharacterSet "#%/<>?#\^`{|}
URLPasswordAllowedCharacterSet "#%/:<>?#[\]^`{|}
URLPathAllowedCharacterSet "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet "#%<>[\]^`{|}
URLUserAllowedCharacterSet "#%/:<>?#[\]^`
If you want a different set of characters to be escaped create a set:
Example with added "=" character:
var originalString = "test/test=42"
var customAllowedSet = NSCharacterSet(charactersInString:"=\"#%/<>?#\\^`{|}").invertedSet
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(customAllowedSet)
println("escapedString: \(escapedString)")
Output:
test%2Ftest%3D42
Example to verify ascii characters not in the set:
func printCharactersInSet(set: NSCharacterSet) {
var characters = ""
let iSet = set.invertedSet
for i: UInt32 in 32..<127 {
let c = Character(UnicodeScalar(i))
if iSet.longCharacterIsMember(i) {
characters = characters + String(c)
}
}
print("characters not in set: \'\(characters)\'")
}
You can use URLComponents to avoid having to manually percent encode your query string:
let scheme = "https"
let host = "www.google.com"
let path = "/search"
let queryItem = URLQueryItem(name: "q", value: "Formula One")
var urlComponents = URLComponents()
urlComponents.scheme = scheme
urlComponents.host = host
urlComponents.path = path
urlComponents.queryItems = [queryItem]
if let url = urlComponents.url {
print(url) // "https://www.google.com/search?q=Formula%20One"
}
extension URLComponents {
init(scheme: String = "https",
host: String = "www.google.com",
path: String = "/search",
queryItems: [URLQueryItem]) {
self.init()
self.scheme = scheme
self.host = host
self.path = path
self.queryItems = queryItems
}
}
let query = "Formula One"
if let url = URLComponents(queryItems: [URLQueryItem(name: "q", value: query)]).url {
print(url) // https://www.google.com/search?q=Formula%20One
}
Swift 4 & 5
To encode a parameter in URL I find using .alphanumerics character set the easiest option:
let urlEncoded = value.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
let url = "http://www.example.com/?name=\(urlEncoded!)"
Using any of the standard Character Sets for URL Encoding (like .urlQueryAllowed or .urlHostAllowed) won't work, because they do not exclude = or & characters.
Note that by using .alphanumerics it will encode some characters that do not need to be encoded (like -, ., _ or ~ -– see 2.3. Unreserved characters in RFC 3986). I find using .alphanumerics simpler than constructing a custom character set and do not mind some additional characters to be encoded. If that bothers you, construct a custom character set as is described in How to percent encode a URL String, like for example:
// Store allowed character set for reuse (computed lazily).
private let urlAllowed: CharacterSet =
.alphanumerics.union(.init(charactersIn: "-._~")) // as per RFC 3986
extension String {
var urlEncoded: String? {
return addingPercentEncoding(withAllowedCharacters: urlAllowed)
}
}
let url = "http://www.example.com/?name=\(value.urlEncoded!)"
Warning: The urlEncoded parameter is force unwrapped. For invalid unicode string it might crash. See Why is the return value of String.addingPercentEncoding() optional?. Instead of force unwrapping urlEncoded! you can use urlEncoded ?? "" or if let urlEncoded = urlEncoded { ... }.
Swift 5:
extension String {
var urlEncoded: String? {
let allowedCharacterSet = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "~-_."))
return self.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
}
}
print("\u{48}ello\u{9}world\u{7}\u{0}".urlEncoded!) // prints Hello%09world%07%00
print("The string ü#foo-bar".urlEncoded!) // prints The%20string%20%C3%BC%40foo-bar
Swift 3:
let originalString = "http://www.ihtc.cc?name=htc&title=iOS开发工程师"
1. encodingQuery:
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)
result:
"http://www.ihtc.cc?name=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88"
2. encodingURL:
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
result:
"http:%2F%2Fwww.ihtc.cc%3Fname=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88"
Swift 4 & 5 (Thanks #sumizome for suggestion. Thanks #FD_ and #derickito for testing)
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: ";/?:#&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
Swift 3
let allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed.remove(charactersIn: ";/?:#&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
Swift 2.2 (Borrowing from Zaph's and correcting for url query key and parameter values)
var allowedQueryParamAndKey = NSCharacterSet(charactersInString: ";/?:#&=+$, ").invertedSet
paramOrKey.stringByAddingPercentEncodingWithAllowedCharacters(allowedQueryParamAndKey)
Example:
let paramOrKey = "https://some.website.com/path/to/page.srf?a=1&b=2#top"
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
// produces:
"https%3A%2F%2Fsome.website.com%2Fpath%2Fto%2Fpage.srf%3Fa%3D1%26b%3D2%23top"
This is a shorter version of Bryan Chen's answer. I'd guess that urlQueryAllowed is allowing the control characters through which is fine unless they form part of the key or value in your query string at which point they need to be escaped.
Swift 4:
It depends by the encoding rules followed by your server.
Apple offer this class method, but it don't report wich kind of RCF protocol it follows.
var escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
Following this useful tool you should guarantee the encoding of these chars for your parameters:
$ (Dollar Sign) becomes %24
& (Ampersand) becomes %26
+ (Plus) becomes %2B
, (Comma) becomes %2C
: (Colon) becomes %3A
; (Semi-Colon) becomes %3B
= (Equals) becomes %3D
? (Question Mark) becomes %3F
# (Commercial A / At) becomes %40
In other words, speaking about URL encoding, you should following the RFC 1738 protocol.
And Swift don't cover the encoding of the + char for example, but it works well with these three # : ? chars.
So, to correctly encoding each your parameter , the .urlHostAllowed option is not enough, you should add also the special chars as for example:
encodedParameter = parameter.replacingOccurrences(of: "+", with: "%2B")
Hope this helps someone who become crazy to search these informations.
Everything is same
var str = CFURLCreateStringByAddingPercentEscapes(
nil,
"test/test",
nil,
"!*'();:#&=+$,/?%#[]",
CFStringBuiltInEncodings.UTF8.rawValue
)
// test%2Ftest
Swift 4.2
A quick one line solution. Replace originalString with the String you want to encode.
var encodedString = originalString.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: "!*'();:#&=+$,/?%#[]{} ").inverted)
Online Playground Demo
This is working for me in Swift 5. The usage case is taking a URL from the clipboard or similar which may already have escaped characters but which also contains Unicode characters which could cause URLComponents or URL(string:) to fail.
First, create a character set that includes all URL-legal characters:
extension CharacterSet {
/// Characters valid in at least one part of a URL.
///
/// These characters are not allowed in ALL parts of a URL; each part has different requirements. This set is useful for checking for Unicode characters that need to be percent encoded before performing a validity check on individual URL components.
static var urlAllowedCharacters: CharacterSet {
// Start by including hash, which isn't in any set
var characters = CharacterSet(charactersIn: "#")
// All URL-legal characters
characters.formUnion(.urlUserAllowed)
characters.formUnion(.urlPasswordAllowed)
characters.formUnion(.urlHostAllowed)
characters.formUnion(.urlPathAllowed)
characters.formUnion(.urlQueryAllowed)
characters.formUnion(.urlFragmentAllowed)
return characters
}
}
Next, extend String with a method to encode URLs:
extension String {
/// Converts a string to a percent-encoded URL, including Unicode characters.
///
/// - Returns: An encoded URL if all steps succeed, otherwise nil.
func encodedUrl() -> URL? {
// Remove preexisting encoding,
guard let decodedString = self.removingPercentEncoding,
// encode any Unicode characters so URLComponents doesn't choke,
let unicodeEncodedString = decodedString.addingPercentEncoding(withAllowedCharacters: .urlAllowedCharacters),
// break into components to use proper encoding for each part,
let components = URLComponents(string: unicodeEncodedString),
// and reencode, to revert decoding while encoding missed characters.
let percentEncodedUrl = components.url else {
// Encoding failed
return nil
}
return percentEncodedUrl
}
}
Which can be tested like:
let urlText = "https://www.example.com/폴더/search?q=123&foo=bar&multi=eggs+and+ham&hangul=한글&spaced=lovely%20spam&illegal=<>#top"
let url = encodedUrl(from: urlText)
Value of url at the end: https://www.example.com/%ED%8F%B4%EB%8D%94/search?q=123&foo=bar&multi=eggs+and+ham&hangul=%ED%95%9C%EA%B8%80&spaced=lovely%20spam&illegal=%3C%3E#top
Note that both %20 and + spacing are preserved, Unicode characters are encoded, the %20 in the original urlText is not double encoded, and the anchor (fragment, or #) remains.
Edit: Now checking for validity of each component.
For Swift 5 to endcode string
func escape(string: String) -> String {
let allowedCharacters = string.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: ":=\"#%/<>?#\\^`{|}").inverted) ?? ""
return allowedCharacters
}
How to use ?
let strEncoded = self.escape(string: "http://www.edamam.com/ontologies/edamam.owl#recipe_e2a1b9bf2d996cbd9875b80612ed9aa4")
print("escapedString: \(strEncoded)")
Had need of this myself, so I wrote a String extension that both allows for URLEncoding strings, as well as the more common end goal, converting a parameter dictionary into "GET" style URL Parameters:
extension String {
func URLEncodedString() -> String? {
var escapedString = self.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
return escapedString
}
static func queryStringFromParameters(parameters: Dictionary<String,String>) -> String? {
if (parameters.count == 0)
{
return nil
}
var queryString : String? = nil
for (key, value) in parameters {
if let encodedKey = key.URLEncodedString() {
if let encodedValue = value.URLEncodedString() {
if queryString == nil
{
queryString = "?"
}
else
{
queryString! += "&"
}
queryString! += encodedKey + "=" + encodedValue
}
}
}
return queryString
}
}
Enjoy!
This one is working for me.
func stringByAddingPercentEncodingForFormData(plusForSpace: Bool=false) -> String? {
let unreserved = "*-._"
let allowed = NSMutableCharacterSet.alphanumericCharacterSet()
allowed.addCharactersInString(unreserved)
if plusForSpace {
allowed.addCharactersInString(" ")
}
var encoded = stringByAddingPercentEncodingWithAllowedCharacters(allowed)
if plusForSpace {
encoded = encoded?.stringByReplacingOccurrencesOfString(" ", withString: "+")
}
return encoded
}
I found above function from this link: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/.
let Url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")
None of these answers worked for me. Our app was crashing when a url contained non-English characters.
let unreserved = "-._~/?%$!:"
let allowed = NSMutableCharacterSet.alphanumeric()
allowed.addCharacters(in: unreserved)
let escapedString = urlString.addingPercentEncoding(withAllowedCharacters: allowed as CharacterSet)
Depending on the parameters of what you are trying to do, you may want to just create your own character set. The above allows for english characters, and -._~/?%$!:
What helped me was that I created a separate NSCharacterSet and used it on an UTF-8 encoded string i.e. textToEncode to generate the required result:
var queryCharSet = NSCharacterSet.urlQueryAllowed
queryCharSet.remove(charactersIn: "+&?,:;#+=$*()")
let utfedCharacterSet = String(utf8String: textToEncode.cString(using: .utf8)!)!
let encodedStr = utfedCharacterSet.addingPercentEncoding(withAllowedCharacters: queryCharSet)!
let paramUrl = "https://api.abc.eu/api/search?device=true&query=\(escapedStr)"
SWIFT 4.2
Sometimes this happened just because there is space in slug OR absence of URL encoding for parameters passing through API URL.
let myString = self.slugValue
let csCopy = CharacterSet(bitmapRepresentation: CharacterSet.urlPathAllowed.bitmapRepresentation)
let escapedString = myString!.addingPercentEncoding(withAllowedCharacters: csCopy)!
//always "info:hello%20world"
print(escapedString)
NOTE : Don't forget to explore about bitmapRepresentation.
version:Swift 5
// space convert to +
let mstring = string.replacingOccurrences(of: " ", with: "+")
// remove special character
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: "!*'\"();:#&=+$,/?%#[]%")
return mstring.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey) ?? mstring
Swift 5
You can try .afURLQueryAllowed option if you want to encode string like below
let testString = "6hAD9/RjY+SnGm&B"
let escodedString = testString.addingPercentEncoding(withAllowedCharacters: .afURLQueryAllowed)
print(escodedString!)
//encoded string will be like en6hAD9%2FRjY%2BSnGm%26B

Creating URL from String [duplicate]

If I encode a string like this:
var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
it doesn't escape the slashes /.
I've searched and found this Objective C code:
NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8 );
Is there an easier way to encode an URL and if not, how do I write this in Swift?
Swift 3
In Swift 3 there is addingPercentEncoding
let originalString = "test/test"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(escapedString!)
Output:
test%2Ftest
Swift 1
In iOS 7 and above there is stringByAddingPercentEncodingWithAllowedCharacters
var originalString = "test/test"
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
println("escapedString: \(escapedString)")
Output:
test%2Ftest
The following are useful (inverted) character sets:
URLFragmentAllowedCharacterSet "#%<>[\]^`{|}
URLHostAllowedCharacterSet "#%/<>?#\^`{|}
URLPasswordAllowedCharacterSet "#%/:<>?#[\]^`{|}
URLPathAllowedCharacterSet "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet "#%<>[\]^`{|}
URLUserAllowedCharacterSet "#%/:<>?#[\]^`
If you want a different set of characters to be escaped create a set:
Example with added "=" character:
var originalString = "test/test=42"
var customAllowedSet = NSCharacterSet(charactersInString:"=\"#%/<>?#\\^`{|}").invertedSet
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(customAllowedSet)
println("escapedString: \(escapedString)")
Output:
test%2Ftest%3D42
Example to verify ascii characters not in the set:
func printCharactersInSet(set: NSCharacterSet) {
var characters = ""
let iSet = set.invertedSet
for i: UInt32 in 32..<127 {
let c = Character(UnicodeScalar(i))
if iSet.longCharacterIsMember(i) {
characters = characters + String(c)
}
}
print("characters not in set: \'\(characters)\'")
}
You can use URLComponents to avoid having to manually percent encode your query string:
let scheme = "https"
let host = "www.google.com"
let path = "/search"
let queryItem = URLQueryItem(name: "q", value: "Formula One")
var urlComponents = URLComponents()
urlComponents.scheme = scheme
urlComponents.host = host
urlComponents.path = path
urlComponents.queryItems = [queryItem]
if let url = urlComponents.url {
print(url) // "https://www.google.com/search?q=Formula%20One"
}
extension URLComponents {
init(scheme: String = "https",
host: String = "www.google.com",
path: String = "/search",
queryItems: [URLQueryItem]) {
self.init()
self.scheme = scheme
self.host = host
self.path = path
self.queryItems = queryItems
}
}
let query = "Formula One"
if let url = URLComponents(queryItems: [URLQueryItem(name: "q", value: query)]).url {
print(url) // https://www.google.com/search?q=Formula%20One
}
Swift 4 & 5
To encode a parameter in URL I find using .alphanumerics character set the easiest option:
let urlEncoded = value.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
let url = "http://www.example.com/?name=\(urlEncoded!)"
Using any of the standard Character Sets for URL Encoding (like .urlQueryAllowed or .urlHostAllowed) won't work, because they do not exclude = or & characters.
Note that by using .alphanumerics it will encode some characters that do not need to be encoded (like -, ., _ or ~ -– see 2.3. Unreserved characters in RFC 3986). I find using .alphanumerics simpler than constructing a custom character set and do not mind some additional characters to be encoded. If that bothers you, construct a custom character set as is described in How to percent encode a URL String, like for example:
// Store allowed character set for reuse (computed lazily).
private let urlAllowed: CharacterSet =
.alphanumerics.union(.init(charactersIn: "-._~")) // as per RFC 3986
extension String {
var urlEncoded: String? {
return addingPercentEncoding(withAllowedCharacters: urlAllowed)
}
}
let url = "http://www.example.com/?name=\(value.urlEncoded!)"
Warning: The urlEncoded parameter is force unwrapped. For invalid unicode string it might crash. See Why is the return value of String.addingPercentEncoding() optional?. Instead of force unwrapping urlEncoded! you can use urlEncoded ?? "" or if let urlEncoded = urlEncoded { ... }.
Swift 5:
extension String {
var urlEncoded: String? {
let allowedCharacterSet = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "~-_."))
return self.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
}
}
print("\u{48}ello\u{9}world\u{7}\u{0}".urlEncoded!) // prints Hello%09world%07%00
print("The string ü#foo-bar".urlEncoded!) // prints The%20string%20%C3%BC%40foo-bar
Swift 3:
let originalString = "http://www.ihtc.cc?name=htc&title=iOS开发工程师"
1. encodingQuery:
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)
result:
"http://www.ihtc.cc?name=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88"
2. encodingURL:
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
result:
"http:%2F%2Fwww.ihtc.cc%3Fname=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88"
Swift 4 & 5 (Thanks #sumizome for suggestion. Thanks #FD_ and #derickito for testing)
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: ";/?:#&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
Swift 3
let allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed.remove(charactersIn: ";/?:#&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
Swift 2.2 (Borrowing from Zaph's and correcting for url query key and parameter values)
var allowedQueryParamAndKey = NSCharacterSet(charactersInString: ";/?:#&=+$, ").invertedSet
paramOrKey.stringByAddingPercentEncodingWithAllowedCharacters(allowedQueryParamAndKey)
Example:
let paramOrKey = "https://some.website.com/path/to/page.srf?a=1&b=2#top"
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
// produces:
"https%3A%2F%2Fsome.website.com%2Fpath%2Fto%2Fpage.srf%3Fa%3D1%26b%3D2%23top"
This is a shorter version of Bryan Chen's answer. I'd guess that urlQueryAllowed is allowing the control characters through which is fine unless they form part of the key or value in your query string at which point they need to be escaped.
Swift 4:
It depends by the encoding rules followed by your server.
Apple offer this class method, but it don't report wich kind of RCF protocol it follows.
var escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
Following this useful tool you should guarantee the encoding of these chars for your parameters:
$ (Dollar Sign) becomes %24
& (Ampersand) becomes %26
+ (Plus) becomes %2B
, (Comma) becomes %2C
: (Colon) becomes %3A
; (Semi-Colon) becomes %3B
= (Equals) becomes %3D
? (Question Mark) becomes %3F
# (Commercial A / At) becomes %40
In other words, speaking about URL encoding, you should following the RFC 1738 protocol.
And Swift don't cover the encoding of the + char for example, but it works well with these three # : ? chars.
So, to correctly encoding each your parameter , the .urlHostAllowed option is not enough, you should add also the special chars as for example:
encodedParameter = parameter.replacingOccurrences(of: "+", with: "%2B")
Hope this helps someone who become crazy to search these informations.
Everything is same
var str = CFURLCreateStringByAddingPercentEscapes(
nil,
"test/test",
nil,
"!*'();:#&=+$,/?%#[]",
CFStringBuiltInEncodings.UTF8.rawValue
)
// test%2Ftest
Swift 4.2
A quick one line solution. Replace originalString with the String you want to encode.
var encodedString = originalString.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: "!*'();:#&=+$,/?%#[]{} ").inverted)
Online Playground Demo
This is working for me in Swift 5. The usage case is taking a URL from the clipboard or similar which may already have escaped characters but which also contains Unicode characters which could cause URLComponents or URL(string:) to fail.
First, create a character set that includes all URL-legal characters:
extension CharacterSet {
/// Characters valid in at least one part of a URL.
///
/// These characters are not allowed in ALL parts of a URL; each part has different requirements. This set is useful for checking for Unicode characters that need to be percent encoded before performing a validity check on individual URL components.
static var urlAllowedCharacters: CharacterSet {
// Start by including hash, which isn't in any set
var characters = CharacterSet(charactersIn: "#")
// All URL-legal characters
characters.formUnion(.urlUserAllowed)
characters.formUnion(.urlPasswordAllowed)
characters.formUnion(.urlHostAllowed)
characters.formUnion(.urlPathAllowed)
characters.formUnion(.urlQueryAllowed)
characters.formUnion(.urlFragmentAllowed)
return characters
}
}
Next, extend String with a method to encode URLs:
extension String {
/// Converts a string to a percent-encoded URL, including Unicode characters.
///
/// - Returns: An encoded URL if all steps succeed, otherwise nil.
func encodedUrl() -> URL? {
// Remove preexisting encoding,
guard let decodedString = self.removingPercentEncoding,
// encode any Unicode characters so URLComponents doesn't choke,
let unicodeEncodedString = decodedString.addingPercentEncoding(withAllowedCharacters: .urlAllowedCharacters),
// break into components to use proper encoding for each part,
let components = URLComponents(string: unicodeEncodedString),
// and reencode, to revert decoding while encoding missed characters.
let percentEncodedUrl = components.url else {
// Encoding failed
return nil
}
return percentEncodedUrl
}
}
Which can be tested like:
let urlText = "https://www.example.com/폴더/search?q=123&foo=bar&multi=eggs+and+ham&hangul=한글&spaced=lovely%20spam&illegal=<>#top"
let url = encodedUrl(from: urlText)
Value of url at the end: https://www.example.com/%ED%8F%B4%EB%8D%94/search?q=123&foo=bar&multi=eggs+and+ham&hangul=%ED%95%9C%EA%B8%80&spaced=lovely%20spam&illegal=%3C%3E#top
Note that both %20 and + spacing are preserved, Unicode characters are encoded, the %20 in the original urlText is not double encoded, and the anchor (fragment, or #) remains.
Edit: Now checking for validity of each component.
For Swift 5 to endcode string
func escape(string: String) -> String {
let allowedCharacters = string.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: ":=\"#%/<>?#\\^`{|}").inverted) ?? ""
return allowedCharacters
}
How to use ?
let strEncoded = self.escape(string: "http://www.edamam.com/ontologies/edamam.owl#recipe_e2a1b9bf2d996cbd9875b80612ed9aa4")
print("escapedString: \(strEncoded)")
Had need of this myself, so I wrote a String extension that both allows for URLEncoding strings, as well as the more common end goal, converting a parameter dictionary into "GET" style URL Parameters:
extension String {
func URLEncodedString() -> String? {
var escapedString = self.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
return escapedString
}
static func queryStringFromParameters(parameters: Dictionary<String,String>) -> String? {
if (parameters.count == 0)
{
return nil
}
var queryString : String? = nil
for (key, value) in parameters {
if let encodedKey = key.URLEncodedString() {
if let encodedValue = value.URLEncodedString() {
if queryString == nil
{
queryString = "?"
}
else
{
queryString! += "&"
}
queryString! += encodedKey + "=" + encodedValue
}
}
}
return queryString
}
}
Enjoy!
This one is working for me.
func stringByAddingPercentEncodingForFormData(plusForSpace: Bool=false) -> String? {
let unreserved = "*-._"
let allowed = NSMutableCharacterSet.alphanumericCharacterSet()
allowed.addCharactersInString(unreserved)
if plusForSpace {
allowed.addCharactersInString(" ")
}
var encoded = stringByAddingPercentEncodingWithAllowedCharacters(allowed)
if plusForSpace {
encoded = encoded?.stringByReplacingOccurrencesOfString(" ", withString: "+")
}
return encoded
}
I found above function from this link: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/.
let Url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")
None of these answers worked for me. Our app was crashing when a url contained non-English characters.
let unreserved = "-._~/?%$!:"
let allowed = NSMutableCharacterSet.alphanumeric()
allowed.addCharacters(in: unreserved)
let escapedString = urlString.addingPercentEncoding(withAllowedCharacters: allowed as CharacterSet)
Depending on the parameters of what you are trying to do, you may want to just create your own character set. The above allows for english characters, and -._~/?%$!:
What helped me was that I created a separate NSCharacterSet and used it on an UTF-8 encoded string i.e. textToEncode to generate the required result:
var queryCharSet = NSCharacterSet.urlQueryAllowed
queryCharSet.remove(charactersIn: "+&?,:;#+=$*()")
let utfedCharacterSet = String(utf8String: textToEncode.cString(using: .utf8)!)!
let encodedStr = utfedCharacterSet.addingPercentEncoding(withAllowedCharacters: queryCharSet)!
let paramUrl = "https://api.abc.eu/api/search?device=true&query=\(escapedStr)"
SWIFT 4.2
Sometimes this happened just because there is space in slug OR absence of URL encoding for parameters passing through API URL.
let myString = self.slugValue
let csCopy = CharacterSet(bitmapRepresentation: CharacterSet.urlPathAllowed.bitmapRepresentation)
let escapedString = myString!.addingPercentEncoding(withAllowedCharacters: csCopy)!
//always "info:hello%20world"
print(escapedString)
NOTE : Don't forget to explore about bitmapRepresentation.
version:Swift 5
// space convert to +
let mstring = string.replacingOccurrences(of: " ", with: "+")
// remove special character
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: "!*'\"();:#&=+$,/?%#[]%")
return mstring.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey) ?? mstring
Swift 5
You can try .afURLQueryAllowed option if you want to encode string like below
let testString = "6hAD9/RjY+SnGm&B"
let escodedString = testString.addingPercentEncoding(withAllowedCharacters: .afURLQueryAllowed)
print(escodedString!)
//encoded string will be like en6hAD9%2FRjY%2BSnGm%26B

How to regex string that includes html

I have this string which is part of a larger string with multiple occurrences of "content" and "/content": I want to capture the whole string between "content ..." and "/content".
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">RATING: ★★★★<br/>
TAGS: Fiction, General, Science Fiction<br/>
SERIES: 20 SienceFiction Greats [19]<br/>
<p class="description">SUMMARY:<br/>Luna is an open colony and the regime is a harsh one....</p></div>
</content>
I want to capture all between "content type="xhtml"" and "/content"
I tried this code:
let regexPattern = "<content type=\"xhtml\">.*</content>"
let result:[String] = matches(for: regexPattern, in: dataString)
but it returns an empty array.
Your regex pattern is close. You do not have any capturing groups within the regex. A capturing group is defined as any pattern between (). So with a little adjustment of the regex you will get a match. The updated Regex should look like this:
let regexPattern = "<content type=\"xhtml\">(.*)<\/content>"
Well I found a solution as the .* pattern captures everything from the first occurrence of "content" to the last occurrence of "/content".
so this is my solution: get an array of "content" occurrences and an array of "/content" occurrences, from these arrays I can calculate the ranges I need from the string
private func getXHTMLContentFromDataString(dataString: String) -> [String] {
var contentStringArray: [String] = []
let startString: String = "<content type=\"xhtml\">"
let endString: String = "</content>"
var isFound = true
var currentString = dataString
while isFound == true && currentString.characters.count > 0 {
if let contentStartRange = currentString.range(of: startString), let contentEndRange = currentString.range(of: endString) {
isFound = true
let contentStr: String = currentString[contentStartRange.upperBound .. < contentEndRange.lowerBound]
contentStringArray.append(contentStr)
currentString = currentString[contentEndRange.upperBound .. <currentString.endIndex]
} else {
isFound = false
}
}
return contentStringArray
}

Remove special characters from the string

I am trying to use an iOS app to dial a number. The problem is that the number is in the following format:
po placeAnnotation.mapItem.phoneNumber!
"‎+1 (832) 831-6486"
I want to get rid of some special characters and I want the following:
832-831-6486
I used the following code but it did not remove anything:
let charactersToRemove = CharacterSet(charactersIn: "()+-")
var telephone = placeAnnotation.mapItem.phoneNumber?.trimmingCharacters(in: charactersToRemove)
Any ideas?
placeAnnotation.mapItem.phoneNumber!.components(separatedBy: CharacterSet.decimalDigits.inverted)
.joined()
Here you go!
I tested and works well.
If you want something similar to CharacterSet with some flexibility, this should work:
let phoneNumber = "1 (832) 831-6486"
let charsToRemove: Set<Character> = Set("()+-".characters)
let newNumberCharacters = String(phoneNumber.characters.filter { !charsToRemove.contains($0) })
print(newNumberCharacters) //prints 1 832 8316486
I know the question is already answered, but to format phone numbers in any way one could use a custom formatter like below
class PhoneNumberFormatter:Formatter
{
var numberFormat:String = "(###) ### ####"
override func string(for obj: Any?) -> String? {
if let number = obj as? NSNumber
{
var input = number as Int64
var output = numberFormat
while output.characters.contains("#")
{
if let range = output.range(of: "#", options: .backwards)
{
output = output.replacingCharacters(in: range, with: "\(input % 10)")
input /= 10
}
else
{
output.replacingOccurrences(of: "#", with: "")
}
}
return output
}
return nil
}
func string(from number:NSNumber) -> String?
{
return string(for: number)
}
}
let phoneNumberFormatter = PhoneNumberFormatter()
//Digits will be filled backwards in place of hashes. It is easy change the custom formatter in anyway
phoneNumberFormatter.numberFormat = "###-##-##-##-##"
phoneNumberFormatter.string(from: 18063783889)
Swift 3
func removeSpecialCharsFromString(_ str: String) -> String {
struct Constants {
static let validChars = Set("1234567890-".characters)
}
return String(str.characters.filter { Constants.validChars.contains($0) })
}
To Use
let str : String = "+1 (832) 831-6486"
let newStr : String = self.removeSpecialCharsFromString(str)
print(newStr)
Note: you can add validChars which you want in string after operation perform.
If you have the number and special character in String format the use following code to remove special character
let numberWithSpecialChar = "1800-180-0000"
let actulNumber = numberWithSpecialChar.components(separatedBy: CharcterSet.decimalDigit.inverted).joined()
Otherwise, If you have the characters and special character in String format the use following code to remove special character
let charactersWithSpecialChar = "A man, a plan, a cat, a ham, a yak, a yam, a hat, a canal-Panama!"
let actulString = charactersWithSpecialChar.components(separatedBy: CharacterSet.letters.inverted).joined(separator: " ")
NSString *str = #"(123)-456-7890";
NSLog(#"String: %#", str);
// Create character set with specified characters
NSMutableCharacterSet *characterSet =
[NSMutableCharacterSet characterSetWithCharactersInString:#"()-"];
// Build array of components using specified characters as separtors
NSArray *arrayOfComponents = [str componentsSeparatedByCharactersInSet:characterSet];
// Create string from the array components
NSString *strOutput = [arrayOfComponents componentsJoinedByString:#""];
NSLog(#"New string: %#", strOutput);

How to take NSRange in swift?

I am very much new to swift language. I am performing some business logic which needs to take NSRange from given String.
Here is my requirement,
Given Amount = "144.44"
Need NSRange of only cent part i.e. after "."
Is there any API available for doing this?
You can do a regex-based search to find the range:
let str : NSString = "123.45"
let rng : NSRange = str.range("(?<=[.])\\d*$", options: .RegularExpressionSearch)
Regular expression "(?<=[.])\\d*$" means "zero or more digits following a dot character '.' via look-behind, all the way to the end of the string $."
If you want a substring from a given string you can use componentsSeparatedByString
Example :
var number: String = "144.44";
var numberresult= number.componentsSeparatedByString(".")
then you can get components as :
var num1: String = numberresult [0]
var num2: String = numberresult [1]
hope it help !!
Use rangeOfString and substringFromIndex:
let string = "123.45"
if let index = string.rangeOfString(".") {
let cents = string.substringFromIndex(index.endIndex)
print("\(cents)")
}
Another version that uses Swift Ranges, rather than NSRange
Define the function that returns an optional Range:
func centsRangeFromString(str: String) -> Range<String.Index>? {
let characters = str.characters
guard let dotIndex = characters.indexOf(".") else { return nil }
return Range(dotIndex.successor() ..< characters.endIndex)
}
Which you can test with:
let r = centsRangeFromString(str)
// I don't recommend force unwrapping here, but this is just an example.
let cents = str.substringWithRange(r!)

Resources