What I'm wanting to do is very simple in C/C++, Java, and so many other languages. All I want to do is be able to specify the width of a string, similar to this:
printf("%-15s", var);
This would create of a field width of 15 characters. I've done a lot of googling. I've tried using COpaquepointeras well as String(format:in various ways with no luck. Any suggestions would be greatly appreciated. I could have missed something when googling.
You can use withCString to quickly convert the string to an array of bytes (technically an UnsafePointer<Int8>):
let str = "Hello world"
let formatted = str.withCString { String(format: "%-15s", $0) }
print("'\(formatted)'")
You are better to do it yourself
let str0 = "alpha"
let length = 20
// right justify
var str20r = String(count: (length - str0.characters.count), repeatedValue: Character(" "))
str20r.appendContentsOf(str0)
// " alpha"
// left justify
var str20l = str0
str20l.appendContentsOf(String(count: (length - str0.characters.count), repeatedValue: Character(" ")))
// "alpha "
if you need something 'more general'
func formatString(str: String, fixLenght: Int, spacer: Character = Character(" "), justifyToTheRigth: Bool = false)->String {
let c = str.characters.count
let start = str.characters.startIndex
let end = str.characters.endIndex
var str = str
if c > fixLenght {
switch justifyToTheRigth {
case true:
let range = start.advancedBy(c - fixLenght)..<end
return String(str.characters[range])
case false:
let range = start..<end.advancedBy(fixLenght - c)
return String(str.characters[range])
}
} else {
var extraSpace = String(count: fixLenght - c, repeatedValue: spacer)
if justifyToTheRigth {
extraSpace.appendContentsOf(str)
return extraSpace
} else {
str.appendContentsOf(extraSpace)
return str
}
}
}
let str = "ABCDEFGH"
let s0 = formatString(str, fixLenght: 3)
let s1 = formatString(str, fixLenght: 3, justifyToTheRigth: true)
let s2 = formatString(str, fixLenght: 10, spacer: Character("-"))
let s3 = formatString(str, fixLenght: 10, spacer: Character("-"), justifyToTheRigth: true)
print(s0)
print(s1)
print(s2)
print(s3)
which prints
ABC
FGH
ABCDEFGH--
--ABCDEFGH
The problem is that Swift strings have variable size elements, so it's ambiguous what "15 characters" is. This is a source of frustration for simple strings — but makes the language more precise when dealing with emoji, regional identifiers, ligatures, etc.
You can convert the Swift string to a C-string and use normal formatters (see Santosh's answer). The "Swift" way to handle strings is to begin at the starting index of the collection of Characters and advance N times. For example:
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let index = alphabet.characters.startIndex.advancedBy(14) // String.CharacterView.Index
let allChars = alphabet.characters.prefixThrough(index) // String.CharacterView
print(String(allChars)) // "ABCDEFGHIJKLMNO\n"
If you want to force padding, you could use an approach like this:
extension String {
func formatted(characterCount characterCount:Int) -> String {
if characterCount < characters.count {
return String(characters.prefixThrough(characters.startIndex.advancedBy(characterCount - 1)))
} else {
return self + String(count: characterCount - characters.count, repeatedValue: " " as Character)
}
}
}
let abc = "ABC"
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
print("!\(abc.formatted(characterCount: 15))!")
// "!ABC !\n"
print("!\(alphabet.formatted(characterCount: 15))!")
// "!ABCDEFGHIJKLMNOP!\n"
Did you try this?
let string1 = "string1"
let string2 = "string2"
let formattedString = String(format: "%-15s - %s",
COpaquePointer(string1.cStringUsingEncoding(NSUTF8StringEncoding)!),
COpaquePointer(string2.cStringUsingEncoding(NSUTF8StringEncoding)!)
)
print(formattedString)
//string1 - string2
We've got a ton of interesting answers now. Thank you everyone. I wrote the following:
func formatLeftJustifiedWidthSpecifier(stringToChange: String, width: Int) -> String {
var newString: String = stringToChange
newString = newString.stringByPaddingToLength(width, withString: " ", startingAtIndex: 0)
return newString
}
From one hand %# is used to format String objects:
import Foundation
var str = "Hello"
print(String(format: "%#", str))
But it does not support the width modifier:
print(String(format: "%-15#", str))
Will still print unpadded text:
"Hello\n"
However there is a modifier %s that seems to work with CStrings:
var cstr = (str as NSString).utf8String //iOS10+ or .UTF8String otherwise
print(String(format: "%-15s", cstr!))
Output:
"Hello \n"
One nice thing is that you can use the same format specification with NSLog:
NSLog("%-15s", cstr!)
To augment the answer above by "Code Different" (thank you!) on Jun 29, 2016, and allow to write something like "hello".center(42); "world".alignLeft(42):
extension String {
// note: symbol names match to nim std/strutils lib
func align (_ boxsz: UInt) -> String {
self.withCString { String(format: "%\(boxsz)s", $0) }
}
func alignLeft (_ boxsz: UInt) -> String {
self.withCString { String(format: "%-\(boxsz)s", $0) }
}
func center (_ boxsz: UInt) -> String {
let n = self.count
guard boxsz > n else { return self }
let padding = boxsz - UInt(n)
let R = padding / 2
guard R > 0 else { return " " + self }
let L = (padding%2 == 0) ? R : (R+1)
return " ".withCString { String(format: "%\(L)s\(self)%\(R)s", $0,$0) }
}
}
I need to generate a random number.
It appears the arc4random function no longer exists as well as the arc4random_uniform function.
The options I have are arc4random_stir(), arc4random_buf(UnsafeMutablePointer<Void>, Int), and arc4random_addrandom(UnsafeMutablePointer<UInt8>, Int32).
I can't find any docs on the functions and no comments in the header files give hints.
let randomIntFrom0To10 = Int.random(in: 1..<10)
let randomFloat = Float.random(in: 0..<1)
// if you want to get a random element in an array
let greetings = ["hey", "hi", "hello", "hola"]
greetings.randomElement()
You could try as well:
let diceRoll = Int(arc4random_uniform(UInt32(6)))
I had to add "UInt32" to make it work.
Just call this function and provide minimum and maximum range of number and you will get a random number.
eg.like randomNumber(MIN: 0, MAX: 10) and You will get number between 0 to 9.
func randomNumber(MIN: Int, MAX: Int)-> Int{
return Int(arc4random_uniform(UInt32(MAX-MIN)) + UInt32(MIN));
}
Note:- You will always get output an Integer number.
After some investigation I wrote this:
import Foundation
struct Math {
private static var seeded = false
static func randomFractional() -> CGFloat {
if !Math.seeded {
let time = Int(NSDate().timeIntervalSinceReferenceDate)
srand48(time)
Math.seeded = true
}
return CGFloat(drand48())
}
}
Now you can just do Math.randomFraction() to get random numbers [0..1[ without having to remember seeding first. Hope this helps someone :o)
Update with swift 4.2 :
let randomInt = Int.random(in: 1..<5)
let randomFloat = Float.random(in: 1..<10)
let randomDouble = Double.random(in: 1...100)
let randomCGFloat = CGFloat.random(in: 1...1000)
Another option is to use the xorshift128plus algorithm:
func xorshift128plus(seed0 : UInt64, _ seed1 : UInt64) -> () -> UInt64 {
var state0 : UInt64 = seed0
var state1 : UInt64 = seed1
if state0 == 0 && state1 == 0 {
state0 = 1 // both state variables cannot be 0
}
func rand() -> UInt64 {
var s1 : UInt64 = state0
let s0 : UInt64 = state1
state0 = s0
s1 ^= s1 << 23
s1 ^= s1 >> 17
s1 ^= s0
s1 ^= s0 >> 26
state1 = s1
return UInt64.addWithOverflow(state0, state1).0
}
return rand
}
This algorithm has a period of 2^128 - 1 and passes all the tests of the BigCrush test suite. Note that while this is a high-quality pseudo-random number generator with a long period, it is not a cryptographically secure random number generator.
You could seed it from the current time or any other random source of entropy. For example, if you had a function called urand64() that read a UInt64 from /dev/urandom, you could use it like this:
let rand = xorshift128plus(urand64(), urand64())
for _ in 1...10 {
print(rand())
}
let MAX : UInt32 = 9
let MIN : UInt32 = 1
func randomNumber()
{
var random_number = Int(arc4random_uniform(MAX) + MIN)
print ("random = ", random_number);
}
In Swift 3 :
It will generate random number between 0 to limit
let limit : UInt32 = 6
print("Random Number : \(arc4random_uniform(limit))")
My implementation as an Int extension. Will generate random numbers in range from..<to
public extension Int {
static func random(from: Int, to: Int) -> Int {
guard to > from else {
assertionFailure("Can not generate negative random numbers")
return 0
}
return Int(arc4random_uniform(UInt32(to - from)) + UInt32(from))
}
}
This is how I get a random number between 2 int's!
func randomNumber(MIN: Int, MAX: Int)-> Int{
var list : [Int] = []
for i in MIN...MAX {
list.append(i)
}
return list[Int(arc4random_uniform(UInt32(list.count)))]
}
usage:
print("My Random Number is: \(randomNumber(MIN:-10,MAX:10))")
Another option is to use GKMersenneTwisterRandomSource from GameKit. The docs say:
A deterministic pseudo-random source that generates random numbers
based on a mersenne twister algorithm. This is a deterministic random
source suitable for creating reliable gameplay mechanics. It is
slightly slower than an Arc4 source, but more random, in that it has a
longer period until repeating sequences. While deterministic, this is
not a cryptographic random source. It is however suitable for
obfuscation of gameplay data.
import GameKit
let minValue = 0
let maxValue = 100
var randomDistribution: GKRandomDistribution?
let randomSource = GKMersenneTwisterRandomSource()
randomDistribution = GKRandomDistribution(randomSource: randomSource, lowestValue: minValue, highestValue: maxValue)
let number = randomDistribution?.nextInt() ?? 0
print(number)
Example taken from Apple's sample code: https://github.com/carekit-apple/CareKit/blob/master/CareKitPrototypingTool/OCKPrototyper/CareKitPatient/RandomNumberGeneratorHelper.swift
I'm late to the party 🤩🎉
Using a function that allows you to change the size of the array and the range selection on the fly is the most versatile method. You can also use map so it's very concise. I use it in all of my performance testing/bench marking.
elements is the number of items in the array
only including numbers from 0...max
func randArr(_ elements: Int, _ max: Int) -> [Int] {
return (0..<elements).map{ _ in Int.random(in: 0...max) }
}
Code Sense / Placeholders look like this.
randArr(elements: Int, max: Int)
10 elements in my array ranging from 0 to 1000.
randArr(10, 1000) // [554, 8, 54, 87, 10, 33, 349, 888, 2, 77]
you can use this in specific rate:
let die = [1, 2, 3, 4, 5, 6]
let firstRoll = die[Int(arc4random_uniform(UInt32(die.count)))]
let secondRoll = die[Int(arc4random_uniform(UInt32(die.count)))]
Lets Code with Swift for the random number or random string :)
let quotes: NSArray = ["R", "A", "N", "D", "O", "M"]
let randomNumber = arc4random_uniform(UInt32(quotes.count))
let quoteString = quotes[Int(randomNumber)]
print(quoteString)
it will give you output randomly.
Don't forget that some numbers will repeat! so you need to do something like....
my totalQuestions was 47.
func getRandomNumbers(totalQuestions:Int) -> NSMutableArray
{
var arrayOfRandomQuestions: [Int] = []
print("arraySizeRequired = 40")
print("totalQuestions = \(totalQuestions)")
//This will output a 40 random numbers between 0 and totalQuestions (47)
while arrayOfRandomQuestions.count < 40
{
let limit: UInt32 = UInt32(totalQuestions)
let theRandomNumber = (Int(arc4random_uniform(limit)))
if arrayOfRandomQuestions.contains(theRandomNumber)
{
print("ping")
}
else
{
//item not found
arrayOfRandomQuestions.append(theRandomNumber)
}
}
print("Random Number set = \(arrayOfRandomQuestions)")
print("arrayOutputCount = \(arrayOfRandomQuestions.count)")
return arrayOfRandomQuestions as! NSMutableArray
}
look, i had the same problem but i insert
the function as a global variable
as
var RNumber = Int(arc4random_uniform(9)+1)
func GetCase(){
your code
}
obviously this is not efficent, so then i just copy and paste the code into the function so it could be reusable, then xcode suggest me to set the var as constant so my code were
func GetCase() {
let RNumber = Int(arc4random_uniform(9)+1)
if categoria == 1 {
}
}
well thats a part of my code so xcode tell me something of inmutable and initialization but, it build the app anyway and that advice simply dissapear
hope it helps
I have not yet been able to figure out how to get a substring of a String in Swift:
var str = “Hello, playground”
func test(str: String) -> String {
return str.substringWithRange( /* What goes here? */ )
}
test (str)
I'm not able to create a Range in Swift. Autocomplete in the Playground isn’t super helpful - this is what it suggests:
return str.substringWithRange(aRange: Range<String.Index>)
I haven't found anything in the Swift Standard Reference Library that helps. Here was another wild guess:
return str.substringWithRange(Range(0, 1))
And this:
let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)
I've seen other answers (Finding index of character in Swift String) that seem to suggest that since String is a bridge type for NSString, the "old" methods should work, but it's not clear how - e.g., this doesn't work either (doesn't appear to be valid syntax):
let x = str.substringWithRange(NSMakeRange(0, 3))
Thoughts?
You can use the substringWithRange method. It takes a start and end String.Index.
var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex)) //"Hello, playground"
To change the start and end index, use advancedBy(n).
var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(2), end: str.endIndex.advancedBy(-1))) //"llo, playgroun"
You can also still use the NSString method with NSRange, but you have to make sure you are using an NSString like this:
let myNSString = str as NSString
myNSString.substringWithRange(NSRange(location: 0, length: 3))
Note: as JanX2 mentioned, this second method is not safe with unicode strings.
Swift 2
Simple
let str = "My String"
let subStr = str[str.startIndex.advancedBy(3)...str.startIndex.advancedBy(7)]
//"Strin"
Swift 3
let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)
str[startIndex...endIndex] // "Strin"
str.substring(to: startIndex) // "My "
str.substring(from: startIndex) // "String"
Swift 4
substring(to:) and substring(from:) are deprecated in Swift 4.
String(str[..<startIndex]) // "My "
String(str[startIndex...]) // "String"
String(str[startIndex...endIndex]) // "Strin"
At the time I'm writing, no extension is perfectly Swift 4.2 compatible, so here is one that covers all the needs I could think of:
extension String {
func substring(from: Int?, to: Int?) -> String {
if let start = from {
guard start < self.count else {
return ""
}
}
if let end = to {
guard end >= 0 else {
return ""
}
}
if let start = from, let end = to {
guard end - start >= 0 else {
return ""
}
}
let startIndex: String.Index
if let start = from, start >= 0 {
startIndex = self.index(self.startIndex, offsetBy: start)
} else {
startIndex = self.startIndex
}
let endIndex: String.Index
if let end = to, end >= 0, end < self.count {
endIndex = self.index(self.startIndex, offsetBy: end + 1)
} else {
endIndex = self.endIndex
}
return String(self[startIndex ..< endIndex])
}
func substring(from: Int) -> String {
return self.substring(from: from, to: nil)
}
func substring(to: Int) -> String {
return self.substring(from: nil, to: to)
}
func substring(from: Int?, length: Int) -> String {
guard length > 0 else {
return ""
}
let end: Int
if let start = from, start > 0 {
end = start + length - 1
} else {
end = length - 1
}
return self.substring(from: from, to: end)
}
func substring(length: Int, to: Int?) -> String {
guard let end = to, end > 0, length > 0 else {
return ""
}
let start: Int
if let end = to, end - length > 0 {
start = end - length + 1
} else {
start = 0
}
return self.substring(from: start, to: to)
}
}
And then, you can use:
let string = "Hello,World!"
string.substring(from: 1, to: 7)gets you: ello,Wo
string.substring(to: 7)gets you: Hello,Wo
string.substring(from: 3)gets you: lo,World!
string.substring(from: 1, length: 4)gets you: ello
string.substring(length: 4, to: 7)gets you: o,Wo
Updated substring(from: Int?, length: Int) to support starting from zero.
NOTE: #airspeedswift makes some very insightful points on the trade-offs of this approach, particularly the hidden performance impacts. Strings are not simple beasts, and getting to a particular index may take O(n) time, which means a loop that uses a subscript can be O(n^2). You have been warned.
You just need to add a new subscript function that takes a range and uses advancedBy() to walk to where you want:
import Foundation
extension String {
subscript (r: Range<Int>) -> String {
get {
let startIndex = self.startIndex.advancedBy(r.startIndex)
let endIndex = startIndex.advancedBy(r.endIndex - r.startIndex)
return self[Range(start: startIndex, end: endIndex)]
}
}
}
var s = "Hello, playground"
println(s[0...5]) // ==> "Hello,"
println(s[0..<5]) // ==> "Hello"
(This should definitely be part of the language. Please dupe rdar://17158813)
For fun, you can also add a + operator onto the indexes:
func +<T: ForwardIndex>(var index: T, var count: Int) -> T {
for (; count > 0; --count) {
index = index.succ()
}
return index
}
s.substringWithRange(s.startIndex+2 .. s.startIndex+5)
(I don't know yet if this one should be part of the language or not.)
SWIFT 2.0
simple:
let myString = "full text container"
let substring = myString[myString.startIndex..<myString.startIndex.advancedBy(3)] // prints: ful
SWIFT 3.0
let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful
SWIFT 4.0
Substring operations return an instance of the Substring type, instead of String.
let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful
// Convert the result to a String for long-term storage.
let newString = String(substring)
It is much more simple than any of the answers here, once you find the right syntax.
I want to take away the [ and ]
let myString = "[ABCDEFGHI]"
let startIndex = advance(myString.startIndex, 1) //advance as much as you like
let endIndex = advance(myString.endIndex, -1)
let range = startIndex..<endIndex
let myNewString = myString.substringWithRange( range )
result will be "ABCDEFGHI"
the startIndex and endIndex could also be used in
let mySubString = myString.substringFromIndex(startIndex)
and so on!
PS: As indicated in the remarks, there are some syntax changes in swift 2 which comes with xcode 7 and iOS9!
Please look at this page
For example to find the first name (up to the first space) in my full name:
let name = "Joris Kluivers"
let start = name.startIndex
let end = find(name, " ")
if end {
let firstName = name[start..end!]
} else {
// no space found
}
start and end are of type String.Index here and are used to create a Range<String.Index> and used in the subscript accessor (if a space is found at all in the original string).
It's hard to create a String.Index directly from an integer position as used in the opening post. This is because in my name each character would be of equal size in bytes. But characters using special accents in other languages could have used several more bytes (depending on the encoding used). So what byte should the integer refer to?
It's possible to create a new String.Index from an existing one using the methods succ and pred which will make sure the correct number of bytes are skipped to get to the next code point in the encoding. However in this case it's easier to search for the index of the first space in the string to find the end index.
Since String is a bridge type for NSString, the "old" methods should work, but it's not clear how - e.g., this doesn't work either (doesn't appear to be valid syntax):
let x = str.substringWithRange(NSMakeRange(0, 3))
To me, that is the really interesting part of your question. String is bridged to NSString, so most NSString methods do work directly on a String. You can use them freely and without thinking. So, for example, this works just as you expect:
// delete all spaces from Swift String stateName
stateName = stateName.stringByReplacingOccurrencesOfString(" ", withString:"")
But, as so often happens, "I got my mojo workin' but it just don't work on you." You just happened to pick one of the rare cases where a parallel identically named Swift method exists, and in a case like that, the Swift method overshadows the Objective-C method. Thus, when you say str.substringWithRange, Swift thinks you mean the Swift method rather than the NSString method — and then you are hosed, because the Swift method expects a Range<String.Index>, and you don't know how to make one of those.
The easy way out is to stop Swift from overshadowing like this, by casting explicitly:
let x = (str as NSString).substringWithRange(NSMakeRange(0, 3))
Note that no significant extra work is involved here. "Cast" does not mean "convert"; the String is effectively an NSString. We are just telling Swift how to look at this variable for purposes of this one line of code.
The really weird part of this whole thing is that the Swift method, which causes all this trouble, is undocumented. I have no idea where it is defined; it is not in the NSString header and it's not in the Swift header either.
The short answer is that this is really hard in Swift right now. My hunch is that there is still a bunch of work for Apple to do on convenience methods for things like this.
String.substringWithRange() is expecting a Range<String.Index> parameter, and as far as I can tell there isn't a generator method for the String.Index type. You can get String.Index values back from aString.startIndex and aString.endIndex and call .succ() or .pred() on them, but that's madness.
How about an extension on the String class that takes good old Ints?
extension String {
subscript (r: Range<Int>) -> String {
get {
let subStart = advance(self.startIndex, r.startIndex, self.endIndex)
let subEnd = advance(subStart, r.endIndex - r.startIndex, self.endIndex)
return self.substringWithRange(Range(start: subStart, end: subEnd))
}
}
func substring(from: Int) -> String {
let end = countElements(self)
return self[from..<end]
}
func substring(from: Int, length: Int) -> String {
let end = from + length
return self[from..<end]
}
}
let mobyDick = "Call me Ishmael."
println(mobyDick[8...14]) // Ishmael
let dogString = "This 🐶's name is Patch."
println(dogString[5..<6]) // 🐶
println(dogString[5...5]) // 🐶
println(dogString.substring(5)) // 🐶's name is Patch.
println(dogString.substring(5, length: 1)) // 🐶
Update: Swift beta 4 resolves the issues below!
As it stands [in beta 3 and earlier], even Swift-native strings have some issues with handling Unicode characters. The dog icon above worked, but the following doesn't:
let harderString = "1:1️⃣"
for character in harderString {
println(character)
}
Output:
1
:
1
️
⃣
In new Xcode 7.0 use
//: Playground - noun: a place where people can play
import UIKit
var name = "How do you use String.substringWithRange?"
let range = name.startIndex.advancedBy(0)..<name.startIndex.advancedBy(10)
name.substringWithRange(range)
//OUT:
You can use this extensions to improve substringWithRange
Swift 2.3
extension String
{
func substringWithRange(start: Int, end: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if end < 0 || end > self.characters.count
{
print("end index \(end) out of bounds")
return ""
}
let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end))
return self.substringWithRange(range)
}
func substringWithRange(start: Int, location: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if location < 0 || start + location > self.characters.count
{
print("end index \(start + location) out of bounds")
return ""
}
let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location))
return self.substringWithRange(range)
}
}
Swift 3
extension String
{
func substring(start: Int, end: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if end < 0 || end > self.characters.count
{
print("end index \(end) out of bounds")
return ""
}
let startIndex = self.characters.index(self.startIndex, offsetBy: start)
let endIndex = self.characters.index(self.startIndex, offsetBy: end)
let range = startIndex..<endIndex
return self.substring(with: range)
}
func substring(start: Int, location: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if location < 0 || start + location > self.characters.count
{
print("end index \(start + location) out of bounds")
return ""
}
let startIndex = self.characters.index(self.startIndex, offsetBy: start)
let endIndex = self.characters.index(self.startIndex, offsetBy: start + location)
let range = startIndex..<endIndex
return self.substring(with: range)
}
}
Usage:
let str = "Hello, playground"
let substring1 = str.substringWithRange(0, end: 5) //Hello
let substring2 = str.substringWithRange(7, location: 10) //playground
Sample Code for how to get substring in Swift 2.0
(i) Substring from starting index
Input:-
var str = "Swift is very powerful language!"
print(str)
str = str.substringToIndex(str.startIndex.advancedBy(5))
print(str)
Output:-
Swift is very powerful language!
Swift
(ii) Substring from particular index
Input:-
var str = "Swift is very powerful language!"
print(str)
str = str.substringFromIndex(str.startIndex.advancedBy(6)).substringToIndex(str.startIndex.advancedBy(2))
print(str)
Output:-
Swift is very powerful language!
is
I hope it will help you!
Easy solution with little code.
Make an extension that includes basic subStringing that nearly all other languages have:
extension String {
func subString(start: Int, end: Int) -> String {
let startIndex = self.index(self.startIndex, offsetBy: start)
let endIndex = self.index(startIndex, offsetBy: end)
let finalString = self.substring(from: startIndex)
return finalString.substring(to: endIndex)
}
}
Simply call this with
someString.subString(start: 0, end: 6)
This works in my playground :)
String(seq: Array(str)[2...4])
Updated for Xcode 7. Adds String extension:
Use:
var chuck: String = "Hello Chuck Norris"
chuck[6...11] // => Chuck
Implementation:
extension String {
/**
Subscript to allow for quick String substrings ["Hello"][0...1] = "He"
*/
subscript (r: Range<Int>) -> String {
get {
let start = self.startIndex.advancedBy(r.startIndex)
let end = self.startIndex.advancedBy(r.endIndex - 1)
return self.substringWithRange(start..<end)
}
}
}
try this in playground
var str:String = "Hello, playground"
let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,8))
it will give you "ello, p"
However where this gets really interesting is that if you make the last index bigger than the string in playground it will show any strings that you defined after str :o
Range() appears to be a generic function so that it needs to know the type it is dealing with.
You also have to give it the actual string your interested in playgrounds as it seems to hold all stings in a sequence one after another with their variable name afterwards.
So
var str:String = "Hello, playground"
var str2:String = "I'm the next string"
let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,49))
gives "ello, playground�str���I'm the next string�str2�"
works even if str2 is defined with a let
:)
Rob Napier had already given a awesome answer using subscript. But i felt one drawback in that as there is no check for out of bound conditions. This can tend to crash. So i modified the extension and here it is
extension String {
subscript (r: Range<Int>) -> String? { //Optional String as return value
get {
let stringCount = self.characters.count as Int
//Check for out of boundary condition
if (stringCount < r.endIndex) || (stringCount < r.startIndex){
return nil
}
let startIndex = self.startIndex.advancedBy(r.startIndex)
let endIndex = self.startIndex.advancedBy(r.endIndex - r.startIndex)
return self[Range(start: startIndex, end: endIndex)]
}
}
}
Output below
var str2 = "Hello, World"
var str3 = str2[0...5]
//Hello,
var str4 = str2[0..<5]
//Hello
var str5 = str2[0..<15]
//nil
So i suggest always to check for the if let
if let string = str[0...5]
{
//Manipulate your string safely
}
In Swift3
For ex: a variable "Duke James Thomas", we need to get "James".
let name = "Duke James Thomas"
let range: Range<String.Index> = name.range(of:"James")!
let lastrange: Range<String.Index> = img.range(of:"Thomas")!
var middlename = name[range.lowerBound..<lstrange.lowerBound]
print (middlename)
Taking a page from Rob Napier, I developed these Common String Extensions, two of which are:
subscript (r: Range<Int>) -> String
{
get {
let startIndex = advance(self.startIndex, r.startIndex)
let endIndex = advance(self.startIndex, r.endIndex - 1)
return self[Range(start: startIndex, end: endIndex)]
}
}
func subString(startIndex: Int, length: Int) -> String
{
var start = advance(self.startIndex, startIndex)
var end = advance(self.startIndex, startIndex + length)
return self.substringWithRange(Range<String.Index>(start: start, end: end))
}
Usage:
"Awesome"[3...7] //"some"
"Awesome".subString(3, length: 4) //"some"
This is how you get a range from a string:
var str = "Hello, playground"
let startIndex = advance(str.startIndex, 1)
let endIndex = advance(startIndex, 8)
let range = startIndex..<endIndex
let substr = str[range] //"ello, pl"
The key point is that you are passing a range of values of type String.Index (this is what advance returns) instead of integers.
The reason why this is necessary, is that strings in Swift don't have random access (because of variable length of Unicode characters basically). You also can't do str[1]. String.Index is designed to work with their internal structure.
You can create an extension with a subscript though, that does this for you, so you can just pass a range of integers (see e.g. Rob Napier's answer).
I tried to come up with something Pythonic.
All the subscripts here are great, but the times I really need something simple is usually when I want to count from back, e.g. string.endIndex.advancedBy(-1)
It supports nil values, for both start and end index, where nil would mean index at 0 for start, string.characters.count for end.
extension String {
var subString: (Int?) -> (Int?) -> String {
return { (start) in
{ (end) in
let startIndex = start ?? 0 < 0 ? self.endIndex.advancedBy(start!) : self.startIndex.advancedBy(start ?? 0)
let endIndex = end ?? self.characters.count < 0 ? self.endIndex.advancedBy(end!) : self.startIndex.advancedBy(end ?? self.characters.count)
return startIndex > endIndex ? "" : self.substringWithRange(startIndex ..< endIndex)
}
}
}
}
let dog = "Dog‼🐶"
print(dog.subString(nil)(-1)) // Dog!!
EDIT
A more elegant solution:
public extension String {
struct Substring {
var start: Int?
var string: String
public subscript(end: Int?) -> String {
let startIndex = start ?? 0 < 0 ? string.endIndex.advancedBy(start!) : string.startIndex.advancedBy(start ?? 0)
let endIndex = end ?? string.characters.count < 0 ? string.endIndex.advancedBy(end!) : string.startIndex.advancedBy(end ?? string.characters.count)
return startIndex > endIndex ? "" : string.substringWithRange(startIndex ..< endIndex)
}
}
public subscript(start: Int?) -> Substring {
return Substring(start: start, string: self)
}
}
let dog = "Dog‼🐶"
print(dog[nil][-1]) // Dog!!
First create the range, then the substring. You can use fromIndex..<toIndex syntax like so:
let range = fullString.startIndex..<fullString.startIndex.advancedBy(15) // 15 first characters of the string
let substring = fullString.substringWithRange(range)
here is a example to get video-Id only .i.e (6oL687G0Iso) from the whole URL in swift
let str = "https://www.youtube.com/watch?v=6oL687G0Iso&list=PLKmzL8Ib1gsT-5LN3V2h2H14wyBZTyvVL&index=2"
var arrSaprate = str.componentsSeparatedByString("v=")
let start = arrSaprate[1]
let rangeOfID = Range(start: start.startIndex,end:start.startIndex.advancedBy(11))
let substring = start[rangeOfID]
print(substring)
let startIndex = text.startIndex
var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4)
let substring = text.substringWithRange(range)
Full sample you can see here
http://www.learnswiftonline.com/reference-guides/string-reference-guide-for-swift/
shows that this works well:
var str = "abcd"
str = str.substringToIndex(1)
Well, I had the same issue and solved with the "bridgeToObjectiveC()" function:
var helloworld = "Hello World!"
var world = helloworld.bridgeToObjectiveC().substringWithRange(NSMakeRange(6,6))
println("\(world)") // should print World!
Please note that in the example, substringWithRange in conjunction with NSMakeRange take the part of the string starting at index 6 (character "W") and finishing at index 6 + 6 positions ahead (character "!")
Cheers.
You can use any of the substring methods in a Swift String extension I wrote https://bit.ly/JString.
var string = "hello"
var sub = string.substringFrom(3) // or string[3...5]
println(sub)// "lo"
If you have an NSRange, bridging to NSString works seamlessly. For example, I was doing some work with UITextFieldDelegate and I quickly wanted to compute the new string value when it asked if it should replace the range.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
println("Got new string: ", newString)
}
Simple extension for String:
extension String {
func substringToIndex(index: Int) -> String {
return self[startIndex...startIndex.advancedBy(min(index, characters.count - 1))]
}
}
If you don't care about performance... this is probably the most concise solution in Swift 4
extension String {
subscript(range: CountableClosedRange<Int>) -> String {
return enumerated().filter{$0.offset >= range.first! && $0.offset < range.last!}
.reduce(""){$0 + String($1.element)}
}
}
It enables you to do something like this:
let myStr = "abcd"
myStr[0..<2] // produces "ab"