warning: 'characters' is deprecated: Please use String or Substring directly - ios

characters - an instance property of String, is deprecated from with Xcode 9.1
It was very useful to get a substring from String by using the characters property but now it has been deprecated and Xcode suggests to use substring. I've tried to check around SO questions and apple developer tutorials/guidelines for the same. But could not see any solution/alternate as suggested.
Here is warning message:
'characters' is deprecated: Please use String or Substring
I've so many string operations are performed/handled using property characters.
Anyone have any idea/info about this update?

Swift 4 introduced changes on string API.
You can just use !stringValue.isEmpty instead of stringValue.characters.count > 0
for more information you get the sample from here
for e.g
let edit = "Summary"
edit.count // 7

Swift 4 vs Swift 3 examples:
let myString = "test"
for char in myString.characters {print(char) } // Swift 3
for char in myString { print(char) } // Swift 4
let length = myString.characters.count // Swift 3
let length = myString.count // Swift 4

One of the most common cases for manipulating strings is with JSON responses. In this example I created an extension in my watch app to drop the last (n) characters of a Bitcoin JSON object.
Swift 3:
func dropLast(_ n: Int = 0) -> String {
return String(characters.dropLast(n))
Xcode 9.1 Error Message:
'characters' is deprecated: Please use String or Substring directly
Xcode is telling us to use the string variable or method directly.
Swift 4:
func dropLast(_ n: Int = 0) -> String {
return String(dropLast(n))
}
Complete Extension:
extension String {
func dropLast(_ n: Int = 0) -> String {
return String(dropLast(n))
}
var dropLast: String {
return dropLast()
}
}
Call:
print("rate:\(response.USDRate)")
let literalMarketPrice = response.USDRate.dropLast(2)
print("literal market price: \(literalMarketPrice)")
Console:
//rate:7,101.0888 //JSON float
//literal market price: 7,101.08 // JSON string literal
Additional Examples:
print("Spell has \(invisibleSpellName.count) characters.")
return String(dropLast(n))
return String(removeLast(n))
Documentation:
You'll often be using common methods such as dropLast() or removeLast() or count so here is the explicit Apple documentation for each method.
droplast()
removelast()
counting characters

Use this characters because String stopped being a collection in Swift 2.0. However this is still valid code in Swift 4 but is no longer necessary now that String is a Collection again.
For example a Swift 4 String now has a direct count property that gives the character count:
// Swift 4
let spString = "Stack"
spString.count // 5
Examples for String and SubString.
String
Swift 4 String now directly get Element that gives the first character of String: (string.characters.first)
let spString = "Stack"
let firstElement = spString.first //S
SubString
Using SubString get first character.
let spstring = "Welcome"
let indexStartOfText = spstring.index(spstring.startIndex, offsetBy: 1)
let sub = spstring.substring(to: indexStartOfText)
print(sub) //W

That warning is just a top of the iceberg, there were a loot of string changes, strings are again a collection of characters, but we got soemthing new and cool, subStrings :)
This is a great read about this:
https://useyourloaf.com/blog/updating-strings-for-swift-4/

Just remove characters
For example:
stringValue.characters.count
to
stringValue.count

You can also use this code for dictionary grouping without using { $0.characters.first! }.
let cities = ["Shanghai": 24_256_800, "Karachi": 23_500_000, "Beijing": 21_516_000, "Seoul": 9_995_000]
let groupedCities = Dictionary(grouping: cities.keys) { $0.first! }
print(groupedCities)

func validatePhoneNumber(number:String) -> Bool{
if number.count < 10. //deprecated ->(number.characters.count)
{
return false;
}else{
return true;
}
}
You use directly .count and characters is deprecated.

Related

UUID in Swift3, but "version 1" style UUID

This question is about Swift.
It's very easy to generate a rfc UUID in Swift getting a Swift String as at this stage Apple have made a Swift method for it...
func sfUUID()->String
{
return UUID().uuidString.lowercased()
}
I need an old-style "version 1" UUID, when using Swift
(Example: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_.28date-time_and_MAC_address.29)
Is there a way to do this in Swift3? ( >9 only)
In Swift, how to get a Version 1 UUID. So, there might be some option I don't know about on the UUID() call, or there's the difficulty of calling a C call and getting the result safely as a String.
Callam's link is the actual answer. Swift can (and in this case must) call C, so the name of the C function is all you really need.
But the "Swift" question here is just how to call a C function from Swift, which is a general skill that's more important than this particular question (and isn't really well explained in the current documentation). So it's worth studying how the following works, and not taking it as just the answer to "how do you generate a v1 UUID in Swift."
var uuid: uuid_t = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
withUnsafeMutablePointer(to: &uuid) {
$0.withMemoryRebound(to: UInt8.self, capacity: 16) {
uuid_generate_time($0)
}
}
let finalUUID = UUID(uuid: uuid)
This is incredibly out of date. Don't do this any more.
I'd delete the answer, but it's ticked!
Swift code which gets to the C call...
func generateVersionOneAkaTimeBasedUUID() -> String {
// figure out the sizes
let uuidSize = MemoryLayout<uuid_t>.size
let uuidStringSize = MemoryLayout<uuid_string_t>.size
// get some ram
let uuidPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: uuidSize)
let uuidStringPointer = UnsafeMutablePointer<Int8>.allocate(capacity: uuidStringSize)
// do the work in C
uuid_generate_time(uuidPointer)
uuid_unparse(uuidPointer, uuidStringPointer)
// make a Swift string while we still have the C stuff
let uuidString = NSString(utf8String: uuidStringPointer) as? String
// avoid leaks
uuidPointer.deallocate(capacity: uuidSize)
uuidStringPointer.deallocate(capacity: uuidStringSize)
assert(uuidString != nil, "uuid (V1 style) failed")
return uuidString ?? ""
}

Hangman Program 2

I have asked a question before about this program, but it seems that not all problems are resolved. I am currently experiencing an error that states: "Cannot convert value of type 'String' to expected argument type '_Element' (aka 'Character') on the "guard let indexInWord" line:
guard let letterIndex = letters.indexOf(sender)
else { return }
let letter = letterArray[letterIndex]
guard let indexInWord = word.characters.indexOf(letter)
else {
print("no such letter in this word")
return
}
// since we have spaces between dashes, we need to calc index this way
let indexInDashedString = indexInWord * 2
var dashString = wordLabel.text
dashString[indexInDashedString] = letter
wordLabel.text = dashString
I tried converting the String 'letter' to Character but it only resulted in more errors. I was wondering how I can possibly convert String to argument type "_Element." Please help.
It is hard to treat a string like a list in swift, mostly because the String.characters is not a typical array. Running a for loop on that works, but if you are looking for a specific character given an index, it is a bit more difficult. What I like doing is adding this function to the string class.
extenstion String {
func getChars() -> [String] {
var chars:[String] = []
for char in characters {
chars.append(String(char))
}
return chars
}
}
I would use this to define a variable when you receive input, then check this instead of String.characters

Cannot find char at position and index of char of a string var in Swift 2

Equivalent functions in Swift 2 of Java's charAt() and indexOf() ?
Firstly read this article about Swift strings and think about exactly what you mean by characters.
You can use the character view (or the utf16 view if that is the sort of characters that you want) of the string to see it as a collection and if you really need to get characters by index (rather than by iteration) you may want to convert it to an array but normally you just need to advance the index.
let myString = "Hello, Stack overflow"
// Note this index is not an integer but an index into a character view (String.CharacterView.Index)
let index = myString.characters.indexOf( "," )
let character = myString[myString.startIndex.advancedBy(4)] // "o"
This is O(n) (where n is the number of characters into the String) as it needs to iterate over the array as Characters may vary in length in the encoding)
Old answer below. The character array may be quicker for repeat access still as the array accesses are O(1) following the one off O(n) conversion to array (n is the array length).
let cIndex = 5
// This initialises a new array from the characters collection
let characters = [Character](myString.characters)
if cIndex < characters.count {
let character = characters[cIndex]
// Use the character here
}
Obviously some simplification is possible if the index is guaranteed to be within the length of the characters but I prefer to demonstrate with some safety on SO.
You can extend the String class with the missing charAt(index: Int) function:
extension String {
func charAt(index: Int) -> Character {
return [Character](characters)[index]
}
}
You have to convert the input string to an Array then return the character from the specific index here is the code
extension String {
func charAt(_ index : Int) -> Character {
let arr = Array(self.characters);
return (arr[index]);
}
}
This will work same as Java's charAt() method you can use it as
var str:String = "Alex"
print(str.charAt(1))
Did you read the NSString documentation? String and NSString are not identical, but as mentioned by this answer most functions are more or less the same. Anyway, the two exact functions you ask for are right there:
Java's charAt:
func characterAtIndex(_ index: Int) -> unichar
Java's indexOf:
func rangeOfString(_ searchString: String) -> NSRange
The NSRange data type contains just 2 variables: location and length that tell you where the substring is in the original string and how long it is. See the documentation.
//Java
"abc".indexOf("b") => 1
//Swift
"abc".rangeOfString("b").location #=> 1
you can used it instead of CharAt() in swift 3:
func charAt(str: String , int :Int)->Character{
str[str.startIndex]
let index = str.index(str.startIndex, offsetBy: int)
return str[index]
}

Swift 2.0 : Count is unavailable access the count property on the collection [duplicate]

Just downloaded Xcode 7 Beta, and this error appeared on enumerate keyword.
for (index, string) in enumerate(mySwiftStringArray)
{
}
Can anyone help me overcome this ?
Also, seems like count() is no longer working for counting length of String.
let stringLength = count(myString)
On above line, compiler says :
'count' is unavailable: access the 'count' property on the collection.
Has Apple has released any programming guide for Swift 2.0 ?
Many global functions have been replaced by protocol extension methods,
a new feature of Swift 2, so enumerate() is now an extension method
for SequenceType:
extension SequenceType {
func enumerate() -> EnumerateSequence<Self>
}
and used as
let mySwiftStringArray = [ "foo", "bar" ]
for (index, string) in mySwiftStringArray.enumerate() {
print(string)
}
And String does no longer conform to SequenceType, you have to
use the characters property to get the collection of Unicode
characters. Also, count() is a protocol extension method of
CollectionType instead of a global function:
let myString = "foo"
let stringLength = myString.characters.count
print(stringLength)
Update for Swift 3: enumerate() has been renamed to enumerated():
let mySwiftStringArray = [ "foo", "bar" ]
for (index, string) in mySwiftStringArray.enumerated() {
print(string)
}
There was an update for Swift 2 on using enumerate().
Instead of enumerate(...), people should use
... .enumerate()
The reason is that many global functions have been replaced by protocol extension methods and they will get an enumerate error.
Hope this helps.
All the best.
n
I know this is a old thread but I've just been messing around with Swift 2.0 and Playgrounds and I came across the same problem I thought I'd share a solution which uses the enumerate() method for a String
// This line works in Swift 1.2
// for (idx, character) in enumerate("A random string, it has a comma.")
// Swift 2.x
let count = inputString.characters
for (idx, character) in count.enumerate() where character == "," {
// Do something with idx
}
Hope this helps
Thanks
Kai

Get the length of a String

How do you get the length of a String? For example, I have a variable defined like:
var test1: String = "Scott"
However, I can't seem to find a length method on the string.
As of Swift 4+
It's just:
test1.count
for reasons.
(Thanks to Martin R)
As of Swift 2:
With Swift 2, Apple has changed global functions to protocol extensions, extensions that match any type conforming to a protocol. Thus the new syntax is:
test1.characters.count
(Thanks to JohnDifool for the heads up)
As of Swift 1
Use the count characters method:
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
println("unusualMenagerie has \(count(unusualMenagerie)) characters")
// prints "unusualMenagerie has 40 characters"
right from the Apple Swift Guide
(note, for versions of Swift earlier than 1.2, this would be countElements(unusualMenagerie) instead)
for your variable, it would be
length = count(test1) // was countElements in earlier versions of Swift
Or you can use test1.utf16count
TLDR:
For Swift 2.0 and 3.0, use test1.characters.count. But, there are a few things you should know. So, read on.
Counting characters in Swift
Before Swift 2.0, count was a global function. As of Swift 2.0, it can be called as a member function.
test1.characters.count
It will return the actual number of Unicode characters in a String, so it's the most correct alternative in the sense that, if you'd print the string and count characters by hand, you'd get the same result.
However, because of the way Strings are implemented in Swift, characters don't always take up the same amount of memory, so be aware that this behaves quite differently than the usual character count methods in other languages.
For example, you can also use test1.utf16.count
But, as noted below, the returned value is not guaranteed to be the same as that of calling count on characters.
From the language reference:
Extended grapheme clusters can be composed of one or more Unicode
scalars. This means that different characters—and different
representations of the same character—can require different amounts of
memory to store. Because of this, characters in Swift do not each take
up the same amount of memory within a string’s representation. As a
result, the number of characters in a string cannot be calculated
without iterating through the string to determine its extended
grapheme cluster boundaries. If you are working with particularly long
string values, be aware that the characters property must iterate over
the Unicode scalars in the entire string in order to determine the
characters for that string.
The count of the characters returned by the characters property is not
always the same as the length property of an NSString that contains
the same characters. The length of an NSString is based on the number
of 16-bit code units within the string’s UTF-16 representation and not
the number of Unicode extended grapheme clusters within the string.
An example that perfectly illustrates the situation described above is that of checking the length of a string containing a single emoji character, as pointed out by n00neimp0rtant in the comments.
var emoji = "👍"
emoji.characters.count //returns 1
emoji.utf16.count //returns 2
Swift 1.2 Update: There's no longer a countElements for counting the size of collections. Just use the count function as a replacement: count("Swift")
Swift 2.0, 3.0 and 3.1:
let strLength = string.characters.count
Swift 4.2 (4.0 onwards): [Apple Documentation - Strings]
let strLength = string.count
Swift 1.1
extension String {
var length: Int { return countElements(self) } //
}
Swift 1.2
extension String {
var length: Int { return count(self) } //
}
Swift 2.0
extension String {
var length: Int { return characters.count } //
}
Swift 4.2
extension String {
var length: Int { return self.count }
}
let str = "Hello"
let count = str.length // returns 5 (Int)
Swift 4
"string".count
;)
Swift 3
extension String {
var length: Int {
return self.characters.count
}
}
usage
"string".length
If you are just trying to see if a string is empty or not (checking for length of 0), Swift offers a simple boolean test method on String
myString.isEmpty
The other side of this coin was people asking in ObjectiveC how to ask if a string was empty where the answer was to check for a length of 0:
NSString is empty
Swift 5.1, 5
let flag = "🇵🇷"
print(flag.count)
// Prints "1" -- Counts the characters and emoji as length 1
print(flag.unicodeScalars.count)
// Prints "2" -- Counts the unicode lenght ex. "A" is 65
print(flag.utf16.count)
// Prints "4"
print(flag.utf8.count)
// Prints "8"
tl;dr If you want the length of a String type in terms of the number of human-readable characters, use countElements(). If you want to know the length in terms of the number of extended grapheme clusters, use endIndex. Read on for details.
The String type is implemented as an ordered collection (i.e., sequence) of Unicode characters, and it conforms to the CollectionType protocol, which conforms to the _CollectionType protocol, which is the input type expected by countElements(). Therefore, countElements() can be called, passing a String type, and it will return the count of characters.
However, in conforming to CollectionType, which in turn conforms to _CollectionType, String also implements the startIndex and endIndex computed properties, which actually represent the position of the index before the first character cluster, and position of the index after the last character cluster, respectively. So, in the string "ABC", the position of the index before A is 0 and after C is 3. Therefore, endIndex = 3, which is also the length of the string.
So, endIndex can be used to get the length of any String type, then, right?
Well, not always...Unicode characters are actually extended grapheme clusters, which are sequences of one or more Unicode scalars combined to create a single human-readable character.
let circledStar: Character = "\u{2606}\u{20DD}" // ☆⃝
circledStar is a single character made up of U+2606 (a white star), and U+20DD (a combining enclosing circle). Let's create a String from circledStar and compare the results of countElements() and endIndex.
let circledStarString = "\(circledStar)"
countElements(circledStarString) // 1
circledStarString.endIndex // 2
In Swift 2.0 count doesn't work anymore. You can use this instead:
var testString = "Scott"
var length = testString.characters.count
Here's something shorter, and more natural than using a global function:
aString.utf16count
I don't know if it's available in beta 1, though. But it's definitely there in beta 2.
Updated for Xcode 6 beta 4, change method utf16count --> utf16Count
var test1: String = "Scott"
var length = test1.utf16Count
Or
var test1: String = "Scott"
var length = test1.lengthOfBytesUsingEncoding(NSUTF16StringEncoding)
As of Swift 1.2 utf16Count has been removed. You should now use the global count() function and pass the UTF16 view of the string. Example below...
let string = "Some string"
count(string.utf16)
For Xcode 7.3 and Swift 2.2.
let str = "🐶"
If you want the number of visual characters:
str.characters.count
If you want the "16-bit code units within the string’s UTF-16 representation":
str.utf16.count
Most of the time, 1 is what you need.
When would you need 2? I've found a use case for 2:
let regex = try! NSRegularExpression(pattern:"🐶",
options: NSRegularExpressionOptions.UseUnixLineSeparators)
let str = "🐶🐶🐶🐶🐶🐶"
let result = regex.stringByReplacingMatchesInString(str,
options: NSMatchingOptions.WithTransparentBounds,
range: NSMakeRange(0, str.utf16.count), withTemplate: "dog")
print(result) // dogdogdogdogdogdog
If you use 1, the result is incorrect:
let result = regex.stringByReplacingMatchesInString(str,
options: NSMatchingOptions.WithTransparentBounds,
range: NSMakeRange(0, str.characters.count), withTemplate: "dog")
print(result) // dogdogdog🐶🐶🐶
You could try like this
var test1: String = "Scott"
var length = test1.bridgeToObjectiveC().length
in Swift 2.x the following is how to find the length of a string
let findLength = "This is a string of text"
findLength.characters.count
returns 24
Swift 2.0:
Get a count: yourString.text.characters.count
Fun example of how this is useful would be to show a character countdown from some number (150 for example) in a UITextView:
func textViewDidChange(textView: UITextView) {
yourStringLabel.text = String(150 - yourStringTextView.text.characters.count)
}
In swift4 I have always used string.count till today I have found that
string.endIndex.encodedOffset
is the better substitution because it is faster - for 50 000 characters string is about 6 time faster than .count. The .count depends on the string length but .endIndex.encodedOffset doesn't.
But there is one NO. It is not good for strings with emojis, it will give wrong result, so only .count is correct.
In Swift 4 :
If the string does not contain unicode characters then use the following
let str : String = "abcd"
let count = str.count // output 4
If the string contains unicode chars then use the following :
let spain = "España"
let count1 = spain.count // output 6
let count2 = spain.utf8.count // output 7
In Xcode 6.1.1
extension String {
var length : Int { return self.utf16Count }
}
I think that brainiacs will change this on every minor version.
Get string value from your textview or textfield:
let textlengthstring = (yourtextview?.text)! as String
Find the count of the characters in the string:
let numberOfChars = textlength.characters.count
Here is what I ended up doing
let replacementTextAsDecimal = Double(string)
if string.characters.count > 0 &&
replacementTextAsDecimal == nil &&
replacementTextHasDecimalSeparator == nil {
return false
}
Swift 4 update comparing with swift 3
Swift 4 removes the need for a characters array on String. This means that you can directly call count on a string without getting characters array first.
"hello".count // 5
Whereas in swift 3, you will have to get characters array and then count element in that array. Note that this following method is still available in swift 4.0 as you can still call characters to access characters array of the given string
"hello".characters.count // 5
Swift 4.0 also adopts Unicode 9 and it can now interprets grapheme clusters. For example, counting on an emoji will give you 1 while in swift 3.0, you may get counts greater than 1.
"👍🏽".count // Swift 4.0 prints 1, Swift 3.0 prints 2
"👨‍❤️‍💋‍👨".count // Swift 4.0 prints 1, Swift 3.0 prints 4
Swift 4
let str = "Your name"
str.count
Remember: Space is also counted in the number
You can get the length simply by writing an extension:
extension String {
// MARK: Use if it's Swift 2
func stringLength(str: String) -> Int {
return str.characters.count
}
// MARK: Use if it's Swift 3
func stringLength(_ str: String) -> Int {
return str.characters.count
}
// MARK: Use if it's Swift 4
func stringLength(_ str: String) -> Int {
return str.count
}
}
Best way to count String in Swift is this:
var str = "Hello World"
var length = count(str.utf16)
String and NSString are toll free bridge so you can use all methods available to NSString with swift String
let x = "test" as NSString
let y : NSString = "string 2"
let lenx = x.count
let leny = y.count
test1.characters.count
will get you the number of letters/numbers etc in your string.
ex:
test1 = "StackOverflow"
print(test1.characters.count)
(prints "13")
Apple made it different from other major language. The current way is to call:
test1.characters.count
However, to be careful, when you say length you mean the count of characters not the count of bytes, because those two can be different when you use non-ascii characters.
For example;
"你好啊hi".characters.count will give you 5 but this is not the count of the bytes.
To get the real count of bytes, you need to do "你好啊hi".lengthOfBytes(using: String.Encoding.utf8). This will give you 11.
Right now (in Swift 2.3) if you use:
myString.characters.count
the method will return a "Distance" type, if you need the method to return an Integer you should type cast like so:
var count = myString.characters.count as Int
my two cents for swift 3/4
If You need to conditionally compile
#if swift(>=4.0)
let len = text.count
#else
let len = text.characters.count
#endif

Resources