I have a swift program in whom I need to read the last 20 digits of a string.
Although I would prefer the last 20 digits the first 20 would also be fine if it makes it any easier.
And a way to read all Digits except for the last 20.
You can use suffix:
String(yourString.characters.suffix(20))
It's interesting because the place you'd expect to find the answer would be the string functions -- where is the Swift equivalent of Javascript's String.substr() for example.
What you want is
String str = ...
str.substringFromIndex(advance(str.startIndex, 20)) // first 20 chars
str.substringFromIndex(advance(str.endIndex, -20)) // last 20 chars
In any case, you'll need to check if the str has fewer than 20 characters and just return the string itself.
You can determine the string length by
count(str) (older Swift versions) or str.characters.count (Swift 1.2)
Related
In swift I know how to set the number of digits after the decimal point when converting a double to a string:
String(format: "%0.2f", someDouble)
Similarly I know how to set the number of digits before the decimal point:
String(format: "%02d", someDouble)
But how can I do both?
I want the string to always have a 00.00 format.
Thanks
You simply combine the two:
String(format: "%05.2f", someDouble)
The 0 means fill with leading zeros as needed.
The 5 means you want the final output to be at least 5 characters, include the decimal point.
The .2 means you want two decimal places.
If this is a number you are showing to a user then you should probably use NumberFormatter so the decimal is properly formatted for the user's locale.
I have apps in Go and Swift which process strings, such as finding substrings and their indices. At first it worked nicely even with multi-byte characters (e.g. emojis), using to Go's utf8.RuneCountInString() and Swift's native String.
But there are some UTF8 characters that break the string length and indices for substrings, e.g. a string "Lorem ππβοΈπ€ ipsum":
Go's utf8.RuneCountInString("Lorem ππβοΈπ€ ipsum") returns 17 and the start index of ipsum is 12.
Swift's "Lorem ππβοΈπ€ ipsum".count returns 16 and the start index of ipsum is 11.
Using Swift String's utf8, utf16 or casting to NSString gives also different lengths and indices. There are also other emojis composed from multiple other emoji's like π¨βπ©βπ§βπ¦ which gives even funnier numbers.
This is with Go 1.8 and Swift 4.1.
Is there any way to get the same string lengths and substrings' indices with same values with Go and Swift?
EDIT
I created a Swift String extension based on #MartinR's great answer:
extension String {
func runesRangeToNSRange(from: Int, to: Int) -> NSRange {
let length = to - from
let start = unicodeScalars.index(unicodeScalars.startIndex, offsetBy: from)
let end = unicodeScalars.index(start, offsetBy: length)
let range = start..<end
return NSRange(range, in: self)
}
}
In Swift a Character is an βextended grapheme cluster,β and each of "π", "π", "βοΈ", "π€", "π¨βπ©βπ§βπ¦" counts as a single character.
I have no experience with Go, but as I understand it from Strings, bytes, runes and characters in Go,
a βruneβ is a Unicode code point, which essentially corresponds to a UnicodeScalar in Swift.
In your example, the difference comes from "βοΈ" which
counts as a single Swift character, but is built from two Unicode scalars:
print("βοΈ".count) // 1
print("βοΈ".unicodeScalars.count) // 2
Here is an example how you can compute the length and offsets in
terms of Unicode scalars:
let s = "Lorem ππβοΈπ€ ipsum"
print(s.unicodeScalars.count) // 17
if let idx = s.range(of: "ipsum") {
print(s.unicodeScalars.distance(from: s.startIndex, to: idx.lowerBound)) // 12
}
As you can see, this gives the same numbers as in your example from Go.
A rune in Go identifies a specific UTF-8 code point; that does not necessarily mean it maps 1:1 to visually distinct characters. Some characters may be made up of multiple runes/code points, therefor counting runes may not give you what you'd expect from a visual inspection of the string. I don't know what "some text".count actually counts in Swift so I can't offer any comparison there.
This question already has answers here:
Number of words in a Swift String for word count calculation
(7 answers)
Closed 5 years ago.
Edit: there is already a question similar to this one but it's for numbers separated by a specific character (Get no. Of words in swift for average calculator). Instead this question is about to get the number of real words in a text, separated in various ways: a line break, some line breaks, a space, more than a space etc.
I would like to get the number of words in a string with Swift 3.
I'm using this code but I get imprecise result because the number is get counting the spaces and new lines instead of the effective number of words.
let str = "Architects and city planners,are \ndesigning buildings to create a better quality of life in our urban areas."
// 18 words, 21 spaces, 2 lines
let components = str.components(separatedBy: .whitespacesAndNewlines)
let a = components.count
print(a)
// 23 instead of 18
Consecutive spaces and newlines aren't coalesced into one generic whitespace region, so you're simply getting a bunch of empty "words" between successive whitespace characters. Get rid of this by filtering out empty strings:
let components = str.components(separatedBy: .whitespacesAndNewlines)
let words = components.filter { !$0.isEmpty }
print(words.count) // 17
The above will print 17 because you haven't included , as a separation character, so the string "planners,are" is treated as one word.
You can break that string up as well by adding punctuation characters to the set of separators like so:
let chararacterSet = CharacterSet.whitespacesAndNewlines.union(.punctuationCharacters)
let components = str.components(separatedBy: chararacterSet)
let words = components.filter { !$0.isEmpty }
print(words.count) // 18
Now you'll see a count of 18 like you expect.
I have already used the text delimiters and item numbers to extract a date from a file name, so I'm clear about how to use these. Unfortunately the date on these particular files are formatted as "yyyyMMdd" and I need to covert the date into format "yyyy-MM-dd". I have been trying to use the offset function to get particular index positions, and I have found several examples of how you would return the offset of particular digits in the string, example:
set theposition to offset of 10 in theString -- this works
(which could return 5 or 7) but I have not found examples of how to call the digits at a specific index:
set _day to offset 7 of file_date_raw -- error
"Finder got an error: Some parameter is missing for offset." number -1701
How would you do this, or is there a totally better way I'm unaware of?
To "call the digits at a specific index", you use:
text 1 thru 4 of myString
If you know that each string has 8 characters in the yyyymmdd format, then you don't need to use 'offset' or any parsing, just add in the -'s, using text x thru y to dissect the string.
set d to "20011018"
set newString to (text 1 thru 4 of d) & "-" & (text 5 thru 6 of d) & "-" & (text 7 thru 8 of d)
I have a word that is being displayed into a label. Could I program it, where it will only show the last 2 characters of the word, or the the first 3 only? How can I do this?
Swift's string APIs can be a little confusing. You get access to the characters of a string via its characters property, on which you can then use prefix() or suffix() to get the substring you want. That subset of characters needs to be converted back to a String:
let str = "Hello, world!"
// first three characters:
let prefixSubstring = String(str.characters.prefix(3))
// last two characters:
let suffixSubstring = String(str.characters.suffix(2))
I agree it is definitely confusing working with String indexing in Swift and they have changed a little bit from Swift 1 to 2 making googling a bit of a challenge but it can actually be quite simple once you get a hang of the methods. You basically need to make it into a two-step process:
1) Find the index you need
2) Advance from there
For example:
let sampleString = "HelloWorld"
let lastThreeindex = sampleString.endIndex.advancedBy(-3)
sampleString.substringFromIndex(lastThreeindex) //prints rld
let secondIndex = sampleString.startIndex.advancedBy(2)
sampleString.substringToIndex(secondIndex) //prints He