swift something wrong with String init(format... method? [duplicate] - string

This question already has an answer here:
cannot find an initializer for type 'String' that accepts an argument list of type '(format: String, argument: UInt32
(1 answer)
Closed 7 years ago.
let elem1 = "1"
let elem2 = "2"
let array = [elem1, elem2]
let format = "%# != %#"
//compiler error
//can't find an initializer for type...
let str = String(format: format, arguments: elem1, elem2)
//no errors but wrong output
//("%# != %#", "1", "2")
let str = String(format: format, _arguments: elem1, elem2)
//runtime error
//fatal error: can't unsafeBitCast between types of different sizes
//this is what I need
let str = String(format: format, arguments: array)
//only this works with the right output
//1 != 2
let str = String(format: format, arguments: [elem1, elem2])
print(str)
tested in xcode7 beta and xcode6.3, I couldn't find a workaround right now

Use this syntax (XCode 7):
import Foundation
let elem1 = "1"
let elem2 = "2"
let format = "%# != %#"
let str = String(format: format, elem1, elem2) // "1 !=2"
print(str) // "1 != 2\n"
The trick is to specify the overloaded ctor with format: and skip arguments: all together.

Related

find the position of character in a substring [duplicate]

This question already has an answer here:
how to find the index of a character in a string from specific position
(1 answer)
Closed 6 years ago.
How can I find the first position of a character in a substring. Not in the string overall, but the first after a specified character position.
Example:
var str = "This is a test string"
//find the position of first "i" after "is"
let position = str.firstPositionOfIAfterPosition(5) // returns 18
I know I can find the overall first position with code below. How can I extend this to start looking only after a specified character position?
let position = str.rangeOfString("i").startIndex
var s = "This is a test string"
var targetRange = s.characters.indices
targetRange.startIndex = targetRange.startIndex.advancedBy(6) // skip past
let r = s.rangeOfString("i", options: [], range: targetRange, locale: nil)
// 18..<19
var str = "This is a test string"
func getIndexAfterString(string: String) -> Int {
let firstIndex = str.rangeOfString(string)?.startIndex.advancedBy(string.characters.count)
let i: Int = str.startIndex.distanceTo(firstIndex!)
let secondIndex = str.substringFromIndex(firstIndex!).rangeOfString("i")?.startIndex
let j: Int = str.startIndex.distanceTo(secondIndex!)
return i + j
}
let index: Int = getIndexAfterString(" is ") //18
Similar to matt's answer, but as String extension and with error handling
extension String {
func firstPositionOf(string: String, afterPosition index: Int) -> String.Index?
{
if self.isEmpty || self.characters.count - 1 < index { return nil }
let subRange = Range<String.Index>(self.startIndex.advancedBy(index + 1)..<self.endIndex)
guard let foundRange = self.rangeOfString(string, options: [], range: subRange) else { return nil }
return foundRange.startIndex
}
}
let str = "This is a test string"
let position = str.firstPositionOf("i", afterPosition:5) // -> 18

String interpolation in Swift

A function in swift takes any numeric type in Swift (Int, Double, Float, UInt, etc).
the function converts the number to a string
the function signature is as follows :
func swiftNumbers <T : NumericType> (number : T) -> String {
//body
}
NumericType is a custom protocol that has been added to numeric types in Swift.
inside the body of the function, the number should be converted to a string:
I use the following
var stringFromNumber = "\(number)"
which is not so elegant, PLUS : if the absolute value of the number is strictly inferior to 0.0001 it gives this:
"\(0.000099)" //"9.9e-05"
or if the number is a big number :
"\(999999999999999999.9999)" //"1e+18"
is there a way to work around this string interpolation limitation? (without using Objective-C)
P.S :
NumberFormater doesn't work either
import Foundation
let number : NSNumber = 9_999_999_999_999_997
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 20
formatter.minimumIntegerDigits = 20
formatter.minimumSignificantDigits = 40
formatter.string(from: number) // "9999999999999996.000000000000000000000000"
let stringFromNumber = String(format: "%20.20f", number) // "0.00000000000000000000"
Swift String Interpolation
1) Adding different types to a string
2) Means the string is created from a mix of constants, variables, literals or expressions.
Example:
let length:Float = 3.14
var breadth = 10
var myString = "Area of a rectangle is length*breadth"
myString = "\(myString) i.e. = \(length)*\(breadth)"
Output:
3.14
10
Area of a rectangle is length*breadth
Area of a rectangle is length*breadth i.e. = 3.14*10
Use the Swift String initializer: String(format: <#String#>, arguments: <#[CVarArgType]#>)
For example:
let stringFromNumber = String(format: "%.2f", number)
String and Characters conforms to StringInterpolationProtocol protocol which provide more power to the strings.
StringInterpolationProtocol - "Represents the contents of a string literal with interpolations while it’s being built up."
String interpolation has been around since the earliest days of Swift, but in Swift 5.0 it’s getting a massive overhaul to make it faster and more powerful.
let name = "Ashwinee Dhakde"
print("Hello, I'm \(name)")
Using the new string interpolation system in Swift 5.0 we can extend String.StringInterpolation to add our own custom interpolations, like this:
extension String.StringInterpolation {
mutating func appendInterpolation(_ value: Date) {
let formatter = DateFormatter()
formatter.dateStyle = .full
let dateString = formatter.string(from: value)
appendLiteral(dateString)
}
}
Usage: print("Today's date is \(Date()).")
We can even provide user-defined names to use String-Interpolation, let's understand with an example.
extension String.StringInterpolation {
mutating func appendInterpolation(JSON JSONData: Data) {
guard
let JSONObject = try? JSONSerialization.jsonObject(with: JSONData, options: []),
let jsonData = try? JSONSerialization.data(withJSONObject: JSONObject, options: .prettyPrinted) else {
appendInterpolation("Invalid JSON data")
return
}
appendInterpolation("\n\(String(decoding: jsonData, as: UTF8.self))")
}
}
print("The JSON is \(JSON: jsonData)")
Whenever we want to provide "JSON" in the string interpolation statement, it will print the .prettyPrinted
Isn't it cool!!

Leading zeros for Int in Swift

I'd like to convert an Int in Swift to a String with leading zeros. For example consider this code:
for myInt in 1 ... 3 {
print("\(myInt)")
}
Currently the result of it is:
1
2
3
But I want it to be:
01
02
03
Is there a clean way of doing this within the Swift standard libraries?
Assuming you want a field length of 2 with leading zeros you'd do this:
import Foundation
for myInt in 1 ... 3 {
print(String(format: "%02d", myInt))
}
output:
01
02
03
This requires import Foundation so technically it is not a part of the Swift language but a capability provided by the Foundation framework. Note that both import UIKit and import Cocoa include Foundation so it isn't necessary to import it again if you've already imported Cocoa or UIKit.
The format string can specify the format of multiple items. For instance, if you are trying to format 3 hours, 15 minutes and 7 seconds into 03:15:07 you could do it like this:
let hours = 3
let minutes = 15
let seconds = 7
print(String(format: "%02d:%02d:%02d", hours, minutes, seconds))
output:
03:15:07
With Swift 5, you may choose one of the three examples shown below in order to solve your problem.
#1. Using String's init(format:_:) initializer
Foundation provides Swift String a init(format:_:) initializer. init(format:_:) has the following declaration:
init(format: String, _ arguments: CVarArg...)
Returns a String object initialized by using a given format string as a template into which the remaining argument values are substituted.
The following Playground code shows how to create a String formatted from Int with at least two integer digits by using init(format:_:):
import Foundation
let string0 = String(format: "%02d", 0) // returns "00"
let string1 = String(format: "%02d", 1) // returns "01"
let string2 = String(format: "%02d", 10) // returns "10"
let string3 = String(format: "%02d", 100) // returns "100"
#2. Using String's init(format:arguments:) initializer
Foundation provides Swift String a init(format:arguments:) initializer. init(format:arguments:) has the following declaration:
init(format: String, arguments: [CVarArg])
Returns a String object initialized by using a given format string as a template into which the remaining argument values are substituted according to the user’s default locale.
The following Playground code shows how to create a String formatted from Int with at least two integer digits by using init(format:arguments:):
import Foundation
let string0 = String(format: "%02d", arguments: [0]) // returns "00"
let string1 = String(format: "%02d", arguments: [1]) // returns "01"
let string2 = String(format: "%02d", arguments: [10]) // returns "10"
let string3 = String(format: "%02d", arguments: [100]) // returns "100"
#3. Using NumberFormatter
Foundation provides NumberFormatter. Apple states about it:
Instances of NSNumberFormatter format the textual representation of cells that contain NSNumber objects and convert textual representations of numeric values into NSNumber objects. The representation encompasses integers, floats, and doubles; floats and doubles can be formatted to a specified decimal position.
The following Playground code shows how to create a NumberFormatter that returns String? from a Int with at least two integer digits:
import Foundation
let formatter = NumberFormatter()
formatter.minimumIntegerDigits = 2
let optionalString0 = formatter.string(from: 0) // returns Optional("00")
let optionalString1 = formatter.string(from: 1) // returns Optional("01")
let optionalString2 = formatter.string(from: 10) // returns Optional("10")
let optionalString3 = formatter.string(from: 100) // returns Optional("100")
For left padding add a string extension like this:
Swift 5.0 +
extension String {
func padLeft(totalWidth: Int, with byString: String) -> String {
let toPad = totalWidth - self.count
if toPad < 1 {
return self
}
return "".padding(toLength: toPad, withPad: byString, startingAt: 0) + self
}
}
Using this method:
for myInt in 1...3 {
print("\(myInt)".padLeft(totalWidth: 2, with: "0"))
}
Swift 3.0+
Left padding String extension similar to padding(toLength:withPad:startingAt:) in Foundation
extension String {
func leftPadding(toLength: Int, withPad: String = " ") -> String {
guard toLength > self.characters.count else { return self }
let padding = String(repeating: withPad, count: toLength - self.characters.count)
return padding + self
}
}
Usage:
let s = String(123)
s.leftPadding(toLength: 8, withPad: "0") // "00000123"
Swift 5
#imanuo answers is already great, but if you are working with an application full of number, you can consider an extension like this:
extension String {
init(withInt int: Int, leadingZeros: Int = 2) {
self.init(format: "%0\(leadingZeros)d", int)
}
func leadingZeros(_ zeros: Int) -> String {
if let int = Int(self) {
return String(withInt: int, leadingZeros: zeros)
}
print("Warning: \(self) is not an Int")
return ""
}
}
In this way you can call wherever:
String(withInt: 3)
// prints 03
String(withInt: 23, leadingZeros: 4)
// prints 0023
"42".leadingZeros(2)
// prints 42
"54".leadingZeros(3)
// prints 054
Using Swift 5’s fancy new extendible interpolation:
extension DefaultStringInterpolation {
mutating func appendInterpolation(pad value: Int, toWidth width: Int, using paddingCharacter: Character = "0") {
appendInterpolation(String(format: "%\(paddingCharacter)\(width)d", value))
}
}
let pieCount = 3
print("I ate \(pad: pieCount, toWidth: 3, using: "0") pies") // => `I ate 003 pies`
print("I ate \(pad: 1205, toWidth: 3, using: "0") pies") // => `I ate 1205 pies`
in Xcode 8.3.2, iOS 10.3
Thats is good to now
Sample1:
let dayMoveRaw = 5
let dayMove = String(format: "%02d", arguments: [dayMoveRaw])
print(dayMove) // 05
Sample2:
let dayMoveRaw = 55
let dayMove = String(format: "%02d", arguments: [dayMoveRaw])
print(dayMove) // 55
The other answers are good if you are dealing only with numbers using the format string, but this is good when you may have strings that need to be padded (although admittedly a little diffent than the question asked, seems similar in spirit). Also, be careful if the string is longer than the pad.
let str = "a str"
let padAmount = max(10, str.count)
String(repeatElement("-", count: padAmount - str.count)) + str
Output "-----a str"
The below code generates a 3 digits string with 0 padding in front:
import Foundation
var randomInt = Int.random(in: 0..<1000)
var str = String(randomInt)
var paddingZero = String(repeating: "0", count: 3 - str.count)
print(str, str.count, paddingZero + str)
Output:
5 1 005
88 2 088
647 3 647
Swift 4* and above you can try this also:
func leftPadding(valueString: String, toLength: Int, withPad: String = " ") -> String {
guard toLength > valueString.count else { return valueString }
let padding = String(repeating: withPad, count: toLength - valueString.count)
return padding + valueString
}
call the function:
leftPadding(valueString: "12", toLength: 5, withPad: "0")
Output:
"00012"
Details
Xcode 9.0.1, swift 4.0
Solutions
Data
import Foundation
let array = [0,1,2,3,4,5,6,7,8]
Solution 1
extension Int {
func getString(prefix: Int) -> String {
return "\(prefix)\(self)"
}
func getString(prefix: String) -> String {
return "\(prefix)\(self)"
}
}
for item in array {
print(item.getString(prefix: 0))
}
for item in array {
print(item.getString(prefix: "0x"))
}
Solution 2
for item in array {
print(String(repeatElement("0", count: 2)) + "\(item)")
}
Solution 3
extension String {
func repeate(count: Int, string: String? = nil) -> String {
if count > 1 {
let repeatedString = string ?? self
return repeatedString + repeate(count: count-1, string: repeatedString)
}
return self
}
}
for item in array {
print("0".repeate(count: 3) + "\(item)")
}
Unlike the other answers that use a formatter, you can also just add an "0" text in front of each number inside of the loop, like this:
for myInt in 1...3 {
println("0" + "\(myInt)")
}
But formatter is often better when you have to add suppose a designated amount of 0s for each seperate number. If you only need to add one 0, though, then it's really just your pick.

Selecting a tuple index using a variable in Swift

That is what i am trying to do:
var i = 0
var string = "abcdef"
for value in string
{
value.[Put value of variable i here] = "a"
i++
}
How can i insert the value of i in the code?
Easiest is probably just convert it to an NSMutableString:
let string = "abcdef".mutableCopy() as NSMutableString
println( "\(string)")
for var i = 0; i < string.length; ++i {
string.replaceCharactersInRange(NSMakeRange(i, 1), withString: "a")
}
println( "\(string)")
Yes, it's a bit ugly but it works.
A much cleaner way is to use Swifts map function:
var string = "abcdef"
let result = map(string) { (c) -> Character in
"a"
}
println("\(result)") // aaaaaa
You should just be able to use the following but this doesn't compile:
map(string) { "a" }
In you comments you mention you want to split up the string on a space, you can just use this for that:
let stringWithSpace = "abcdef 012345"
let splitString = stringWithSpace.componentsSeparatedByString(" ")
println("\(splitString[0])") // abcdef
println("\(splitString[1])") // 012345

Swift - Search in string and sum the numbers

Hey guys I have string "69 - 13" How to detect "-" in the string and how to sum the numbers in the string 69+13=82 ?
There are various method to do that (componentsSeparatedByString, NSScanner, ...).
Here is one using only Swift library functions:
let str = "69 - 13"
// split string into components:
let comps = split(str, { $0 == "-" || $0 == " " }, maxSplit: Int.max, allowEmptySlices: false)
// convert strings to numbers (use zero if the conversion fails):
let nums = map(comps) { $0.toInt() ?? 0 }
// compute the sum:
let sum = reduce(nums, 0) { $0 + $1 }
println(sum)
Here is an updated implementation in Swift 4 that relies on higher order functions to perform the operation:
let string = "69+13"
let number = string.components(separatedBy: CharacterSet.decimalDigits.inverted)
.compactMap({ Int($0) })
.reduce(0, +)
print(number) // 82
The components(separatedBy: CharacterSet.decimalDigits.inverted) removes all non-digit values and creates an array for each group of values (in this case 69 and 13)
Int($0) converts your string value into an Int
compactMap gets rid of any nil values, ensuring that only valid values are left
reduce then sums up the values that remain in your array

Resources