String encoding - Swift - ios

I am using the following method to encode a string in objective - C:
+(NSString*)urlEncoded:(NSString*)string
{ return ((NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes (NULL,(CFStringRef)string, NULL,(CFStringRef)#"! '=();#&+$%#",kCFStringEncodingUTF8 )));}
Is there any counterpart for this method in Swift 2.0 ? I have tried using many solutions present on stack, but none of them could solve my problem.

You probably want to use stringByAddingPercentEncodingWithAllowedCharacters with NSCharacterSet's URL-component specific character sets:
let title = "NSURL / NSURLComponents"
let escapedTitle = title.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
The idea behind those character sets is that they're probably more correct for the uses they describe than any finite set you have. That said, you could use the same method with a set you generate yourself:
let escapeSet = NSCharacterSet(charactersInString: "! '=();#&+$%#")
let string = "sdfT&*w5e#sto([+peW7)%y9pqf])"
let escapedString = string.stringByAddingPercentEncodingWithAllowedCharacters(escapeSet.invertedSet)
// "sdfT%26*w5e%23sto%28[%2BpeW7%29%25y9pqf]%29"

Related

Wrong language code swift

I set the language of the simulator to French. To check the language code, I used a couple of solutions:
let lang = NSLocale.autoupdatingCurrent.languageCode
print(lang)
let pre = Locale.preferredLanguages[0]
print(pre)
The result are:
Optional("en")
fr-US
What I expected to get is:
fr
How can I achieve that?
Try below code,
let requiredString = pre.components(separatedBy: "-").first ?? pre //fr
/*if pre.contains("-"), then requiredString = before("-") else requiredString = pre*/
print(Locale.components(fromIdentifier: Locale.preferredLanguages[0])["kCFLocaleLanguageCodeKey"]!)
this will print language code only.
If you want the Language instead of the Language_Region, then I suggest to take the sub string before the _ from the string to neglect the Region.
(If the string contains no _ then take the entire string since it doesn't contain the region in it)

`CountedSet` initialization issue

I'm comparing the characters contained within two words. In seeking to accomplish this, Set (aka NSSet) seemed like the way to go to accomplish this task. I've discovered it returns false positives on matches, so I am attempting to use CountedSet (aka NSCountedSet) instead.
I'm able to initialize a Set without issue, but I can't get the CountedSet initializer to work. Here's what I've done...
I start with a String:
// Let's say myTextField.text = "test"
let textFieldCharacters = myTextField.text?.characters
// word is a string from the ENABLE list of words
let wordCharacters = word.characters
Then I dump the characters into an Array:
var wordCharactersArray = [Character]()
for character in wordCharacters {
wordCharacterArray.append(character)
}
var textFieldCharactersArray = [Character]()
for character in textFieldCharacters {
wordCharacterArray.append(character)
}
Then I create a Set from the character arrays:
let textFieldSet = Set<Character>(textFieldCharactersArray)
let wordSet = Set<Character>(wordCharactersArray)
Finally, I test to see if the textFieldSet is a superSet of wordSet with the following:
textFieldSet.isSuperset(of: wordSet)
Going back to my example, if myTextField.text is "test", I'm returning values for word whose characters are a superset of the wordSet, but the counts of the individual elements don't match the character counts of myTextField.text
In researching my issue, I've found CountedSet (fka NSCountedSet), which I think would resolve my issue. It has two method signatures:
public convenience init(array: [AnyObject])
public convenience init(set: Set<NSObject>)
I've tried initializing the 2 sets of characters like so:
let textFieldSet = CountedSet(array: textFieldCharacterArray)
let wordSet = CountedSet(array: wordCharacterArray)
I get the following error for the sets
Cannot convert value of type '[Character]' to expected argument type
'[AnyObject]'.
So I tried initializing the set like this:
let textFieldSet = CountedSet(array: textFieldCharacterArray as! [AnyObject])
Which yields the following error:
'AnyObject' is not a subtype of 'Character'
I've also tried to initialize the CountedSet with a Set, per the method signature, but I get errors when I try to do that, too.
Any suggestions how to initialize a CountedSet would be greatly appreciated.
You are correct that if you need to compare not just the presents of elements but also their count, you should use CountedSet, which is a renaming of NSCountedSet for swift 3.0. The problem you are running into is CountedSet can only accept elements that are objects and Characters are not. As Eric D points out in their comment, the easies way to get around this is by mapping your [Character] to [String] which will bridge to [NSString].
You are not running into this problem using Set, because it is a native Swift collection type that initialize with elements of any type. This is why you can initialize a Set with [Character].
To see the difference:
let word = "helo"
let wordCharacters = Array(word.characters)
let wordSet = Set(wordCharacters)
let wordCharStrings = wordCharacters.map{String($0)}
let wordCountedSet = CountedSet(array: wordCharStrings)
let textField = "hello"
let textFieldCharacters = Array(textField.characters)
let textSet = Set(textFieldCharacters)
let textFieldCharStrings = textFieldCharacters.map{String($0)}
let textFieldCountedSet = CountedSet(array: textFieldCharStrings)
textFieldCountedSet.isSubset(of: wordCountedSet as! Set<NSObject>) // returns false, but if word had two or more l's it would return true
textSet.isSubset(of: wordSet) // returns true

Swift 2.0 String with substringWithRange

I am trying to get first char from String. It should be easy but I can't do in Swift 2.0 (with Xcode beta 6).
Get nth character of a string in Swift programming language
I have tried that method also. It use extension but I can't retrieve using that method. May I know how to do?
Two solutions without casting to NSString
let string = "Hello"
let firstChar1 = string.substringToIndex(string.startIndex.successor())
let firstChar2 = string.characters.first
Update for Swift 2:
Since Swift 2 returns Character rather than String a new String must be created.
let firstChar2 = String(string.characters.first!)
Update for Swift 3:
successor() has been replaced with index(after:..)
let firstChar1 = string.substring(to:string.index(after: string.startIndex))
Try this,
let str = "hogehoge"
let text = (str as NSString).substringFromIndex(1) // "ogehoge"
For what it's worth (and for people searching for and finding this topic), without casting the String to NSString, you need to do the following with Swift 2.1:
let myString = "Example String"
let mySubString = myString.substringWithRange(Range<String.Index>(start: myString.startIndex.advanceBy(0), end: myString.startIndex.advanceBy(4)))
print(mySubString) //'Exam'
This would printout "Exam". Must say that it's much more verbose than in Obj-C. And that's saying something... ;-) But it gets the job done and without casting to NSString.
Try this
let myString = "My String" as NSString
myString.substringWithRange(NSRange(location: 0, length: 3))
In Swift 2 a String is not a collection of anything. According to the documentation:
/// `String` is not itself a collection of anything. Instead, it has
/// properties that present the string's contents as meaningful
/// collections:
///
/// - `characters`: a collection of `Character` ([extended grapheme
/// cluster](http://www.unicode.org/glossary/#extended_grapheme_cluster))
/// elements, a unit of text that is meaningful to most humans.
///
/// - `unicodeScalars`: a collection of `UnicodeScalar` ([Unicode
/// scalar
/// values](http://www.unicode.org/glossary/#unicode_scalar_value))
/// the 21-bit codes that are the basic unit of Unicode. These
/// values are equivalent to UTF-32 code units.
///
/// - `utf16`: a collection of `UTF16.CodeUnit`, the 16-bit
/// elements of the string's UTF-16 encoding.
///
/// - `utf8`: a collection of `UTF8.CodeUnit`, the 8-bit
/// elements of the string's UTF-8 encoding.
Assuming you want to find the second character,
var str = "Hello, playground"
let chars = str.characters
let n = 2
let c = str.characters[str.characters.startIndex.advancedBy(n)]
var mySuperCoolString = "Hello, World!!!!!!!!1!!";
println(mySuperCoolString.substringWithRange(Range<String.Index>(start: advance(mySuperCoolString.startIndex, 0), end: advance(mySuperCoolString.startIndex, 1))));
This should print out H
Swift 2.2 and Swift 3.0
let string = "12134"
string.substringWithRange(string.startIndex..<string.startIndex.advancedBy(2))

insert a String inside another String

How can I make this:
var originalString = "http://name.domain.com/image.jpg"
becomes this:
originalString = "http://name.domain.com/image_new.jpg"
I could not find any document about the new Range<String.Index> in Swift.
This is not a problem in Obj-C, but without any reference about Range, it suddenly becomes so confusing.
Thanks.
Edit:
Well, thanks for these solutions. However, let me give you more details about this question.
After uploading an image to server, it responds back with a String link, like above, and the image name is a random string.
The server also generates different versions of uploaded image (like Flickr). In order to get these images, I have to append a suffix into image name, it looks like this:
originalString = "http://image.domain.com/randomName_large.jpg" or "http://image.domain.com/randomName_medium.jpg"
So that's why I need to insert a String into another String. My solution is find the first . by scan the link backwardly and append a suffix before it, but the new Range<String.Index> makes it confusing.
There are some nice and useful methods on NSString that you should be able to use:
let originalString: NSString = "http://name.domain.com/image.jpg"
let extension = originalString.pathExtension // "jpg"
let withoutExt = originalString.stringByDeletingPathExtension() // "http://name.domain.com/image"
let imageName = withoutExt.lastPathComponent // "image"
let withoutFilename = withoutExt.stringByDeletingLastPathComponent() // "http://name.domain.com/"
let newString = withoutFilename
.stringByAppendingPathComponent("\(imageName)_new")
.stringByAppendingPathExtension(extension)
I only typed this into the browser (it's untested) but it should give you an idea...
This can be done with String manipulation functions. But what if the string
is
var originalString = "http://images.domain.com/image.jpg"
? You probably do not want to replace the first or all occurrences of the string
"image" here.
A better tool for this purpose might be NSURLComponents, which lets you
modify all components of a URL separately:
var originalString = "http://name.domain.com/image.jpg"
let urlComps = NSURLComponents(string: originalString)!
urlComps.path = "/image_new.jpg"
originalString = urlComps.URL!.absoluteString!
println(originalString) // http://name.domain.com/image_new.jpg
Why not using string interpolation?
var imageName = "image_new"
originalString = "http://images.domain.com/\(imageName).jpg"

base64EncodedStringWithOptions in Swift fails with compile error

let dataStr = data.base64EncodedStringWithOptions(options: Encoding64CharacterLineLength)
Doesn't compile with "Use of unresolved identifier 'Encoding64CharacterLineLength'"
When I just change the param to zero with
let dataStr = data.base64EncodedStringWithOptions(options: 0)
It gives even stranger error: "Cannot convert the expression of type 'String!' to type 'String!'" I found a way to init NSString with NSData (however, I still can't get the difference between String and NSString), but I'm really curious why these two lines of code don't work.
Unless explicitly given an external name, first argument of a method in Swift is not a named argument. Therefore you should be doing: data.base64EncodedStringWithOptions(x) without the options: part.
If you actually look at the argument type, NSDataBase64EncodingOptions, you'll notice that it is a struct conforming to RawOptionSet with static variables for option constants. Therefore to use them you should do: NSDataBase64EncodingOptions.Encoding64CharacterLineLength
The NSDataBase64EncodingOptions struct (or RawOptionSet in general) is also not convertible from integer literals (like 0). But it does conform to NilLiteralConvertible so if you don't want any options you can pass nil.
Putting it together:
let dataStr = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
or
let dataStr = data.base64EncodedStringWithOptions(nil)
Swift3.0
let dataStr = data.base64EncodedString(options: [])
For Swift 2.x use an array for options:
let dataStr = data.base64EncodedStringWithOptions([.Encoding64CharacterLineLength])
let dataStr = data.base64EncodedStringWithOptions([])
For swift 3.0+ use this ,
var dataStr = data.base64EncodedString(options: .lineLength64Characters)
Swift 3.x
let fileStream = fileData?.base64EncodedString(options: NSData.Base64EncodingOptions.init(rawValue: 0))
You don't have to put in the "options:" identifier in the argument. You DO have to specify that Encoding64CharacterLineLength is a static member of NSDataBase64EncodingOptions, like so:
var dataStr = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let dataStr = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)
Since the default parameter value is set be an empty array…
/// Returns a Base-64 encoded string.
///
/// - parameter options: The options to use for the encoding. Default value is `[]`.
/// - returns: The Base-64 encoded string.
#inlinable public func base64EncodedString(options: Data.Base64EncodingOptions = []) -> String
you just need to call
let dataStr = data.base64EncodedString()

Resources