Swift 2.2 loop through string and get char & index - string

I'm trying to loop through a String get get the characters as well as their index. Sounds easy.. but I'm not finding the correct syntax for doing that.
Here is what I was trying:
let str = "testString"
for (index, char) in str.characters {
print(index)
print(char)
}
or
for (index, char) in enumerate(str.characters) {...}

let str = "testString"
for (index, element) in str.characters.enumerate() {
print(index)
print(element)
}

Swift 4
let str = "Swift 4"
for (index, element) in str.enumerated() {
print(index)
print(element)
}

Related

Swift 5: identify all different substrings in string

I have the following string:
var strOfCharToSort = "azcdczbdxaaczdbbaazdz"
but I'm trying to get the count of the different substrings
for example:
let countofA = strOfCharToSort.filter { $0 == "a" }.count
and it works but I don't know what substrings are in the string I'm loading
I can sort the string:
strOfCharToSort = String(strOfCharToSort.sorted()) \\ result: aaaaabbbcccddddxzzzzz
But my question to guys there is a way to split the string when if finds a different substring?
I'll really appreciate you help.
let strOfCharToSort = "azcdczbdxaaczdbbaazdz"
let setOfChars = Set(strOfCharToSort)
let setOfCharsArray = Array(setOfChars).sorted()
let listOfSortedCharSubstrings = setOfCharsArray.map { (charachter) in
return strOfCharToSort.filter { $0 == charachter }
}
This is a solution to get the sub strings of a sorted character array.
Try This
let StringOfChar = "azcdczbdxaaczdbbaazdz"
let SetOfAllChar = Set(StringOfChar)
for char in SetOfAllChar {
let countofChar = StringOfChar.filter { $0 == char }.count
print("Count of \(char) : \(countofChar)")
}
Output:
Count of d: 4
Count of z: 5
Count of c: 3
Count of b: 3
Count of a: 5
Count of x: 1

String, substring, Range, NSRange in Swift 4

I am using the following code to get a String substring from an NSRange:
func substring(with nsrange: NSRange) -> String? {
guard let range = Range.init(nsrange)
else { return nil }
let start = UTF16Index(range.lowerBound)
let end = UTF16Index(range.upperBound)
return String(utf16[start..<end])
}
(via: https://mjtsai.com/blog/2016/12/19/nsregularexpression-and-swift/)
When I compile with Swift 4 (Xcode 9b4), I get the following errors for the two lines that declare start and end:
'init' is unavailable
'init' was obsoleted in Swift 4.0
I am confused, since I am not using an init.
How can I fix this?
Use Range(_, in:) to convert an NSRange to a Range in Swift 4.
extension String {
func substring(with nsrange: NSRange) -> Substring? {
guard let range = Range(nsrange, in: self) else { return nil }
return self[range]
}
}
With Swift 4 we can get substrings this way.
Substring from index
let originStr = "Test"
let offset = 1
let str = String(originStr.suffix(from: String.Index.init(encodedOffset: offset)))
Substring to index
let originStr = "Test"
let offset = 1
String(self.prefix(index))

Swift How to get integer from string and convert it into integer

I need to extract numbers from string and put them into a new array in Swift.
var str = "I have to buy 3 apples, 7 bananas, 10eggs"
I tried to loop each characters and I have no idea to compare between Characters and Int.
Swift 3/4
let string = "0kaksd020dk2kfj2123"
if let number = Int(string.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()) {
// Do something with this number
}
You can also make an extension like:
extension Int {
static func parse(from string: String) -> Int? {
return Int(string.components(separatedBy: CharacterSet.decimalDigits.inverted).joined())
}
}
And then later use it like:
if let number = Int.parse(from: "0kaksd020dk2kfj2123") {
// Do something with this number
}
First, we split the string so we can process the single items. Then we use NSCharacterSet to select the numbers only.
import Foundation
let str = "I have to buy 3 apples, 7 bananas, 10eggs"
let strArr = str.split(separator: " ")
for item in strArr {
let part = item.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
if let intVal = Int(part) {
print("this is a number -> \(intVal)")
}
}
Swift 4:
let string = "I have to buy 3 apples, 7 bananas, 10eggs"
let stringArray = string.components(separatedBy: CharacterSet.decimalDigits.inverted)
for item in stringArray {
if let number = Int(item) {
print("number: \(number)")
}
}
Using the "regex helper function" from Swift extract regex matches:
func matchesForRegexInText(regex: String!, text: String!) -> [String] {
let regex = NSRegularExpression(pattern: regex,
options: nil, error: nil)!
let nsString = text as NSString
let results = regex.matchesInString(text,
options: nil, range: NSMakeRange(0, nsString.length))
as! [NSTextCheckingResult]
return map(results) { nsString.substringWithRange($0.range)}
}
you can achieve that easily with
let str = "I have to buy 3 apples, 7 bananas, 10eggs"
let numbersAsStrings = matchesForRegexInText("\\d+", str) // [String]
let numbersAsInts = numbersAsStrings.map { $0.toInt()! } // [Int]
println(numbersAsInts) // [3, 7, 10]
The pattern "\d+" matches one or more decimal digit.
Of course the same can be done without the use of a helper function
if you prefer that for whatever reason:
let str = "I have to buy 3 apples, 7 bananas, 10eggs"
let regex = NSRegularExpression(pattern: "\\d+", options: nil, error: nil)!
let nsString = str as NSString
let results = regex.matchesInString(str, options: nil, range: NSMakeRange(0, nsString.length))
as! [NSTextCheckingResult]
let numbers = map(results) { nsString.substringWithRange($0.range).toInt()! }
println(numbers) // [3, 7, 10]
Alternative solution without regular expressions:
let str = "I have to buy 3 apples, 7 bananas, 10eggs"
let digits = "0123456789"
let numbers = split(str, allowEmptySlices: false) { !contains(digits, $0) }
.map { $0.toInt()! }
println(numbers) // [3, 7, 10]
let str = "Hello 1, World 62"
let intString = str.componentsSeparatedByCharactersInSet(
NSCharacterSet
.decimalDigitCharacterSet()
.invertedSet)
.joinWithSeparator("")
That will get you a string with all the number then you can just do this:
let int = Int(intString)
Just make sure you unwrap it since let int = Int(intString) is an optional.
For me makes more sense to have it as a String extension, probably it's a matter of tastes:
extension String {
func parseToInt() -> Int? {
return Int(self.components(separatedBy: CharacterSet.decimalDigits.inverted).joined())
}
}
So can be used like this:
if let number = "0kaksd020dk2kfj2123".parseToInt() {
// Do something with this number
}
Adapting from #flashadvanced's answer,
I found that the following is shorter and simpler for me.
let str = "I have to buy 3 apples, 7 bananas, 10eggs"
let component = str.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let list = component.filter({ $0 != "" }) // filter out all the empty strings in the component
print(list)
Tried in in the play ground and it works
Hope it helps :)
Swift 2.2
let strArr = str.characters.split{$0 == " "}.map(String.init)
for item in strArr {
let components = item.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let part = components.joinWithSeparator("")
if let intVal = Int(part) {
print("this is a number -> \(intVal)")
}
}
// This will only work with single digit numbers. Works with “10eggs” (no space between number and word
var str = "I have to buy 3 apples, 7 bananas, 10eggs"
var ints: [Int] = []
for char:Character in str {
if let int = "\(char)".toInt(){
ints.append(int)
}
}
The trick here is that you can check if a string is an integer (but you can’t check if a character is).
By looping though every character of the string, use string interpolation to create a string from the character and check if that string cas be casted as a integer.
If it can be, add it to the array.
// This will work with multi digit numbers. Does NOT work with “10 eggs” (has to have a space between number and word)
var str = "I have to buy 3 apples, 7 bananas, 10 eggs"
var ints: [Int] = []
var strArray = split(str) {$0 == " "}
for subString in strArray{
if let int = subString.toInt(){
ints.append(int)
}
}
Here we split the string at any space and create an array of every substring that is in the long string.
We again check every string to see if it is (or can be casted as) an integer.
Thanks for everyone who answered to my question.
I was looking for a block of code which uses only swift grammar, because I'm learning grammar only now..
I got an answer for my question.Maybe it is not an easier way to solve, but it uses only swift language.
var article = "I have to buy 3 apples, 7 bananas, 10 eggs"
var charArray = Array(article)
var unitValue = 0
var total = 0
for char in charArray.reverse() {
if let number = "\(char)".toInt() {
if unitValue==0 {
unitValue = 1
}
else {
unitValue *= 10
}
total += number*unitValue
}
else {
unitValue = 0
}
}
println("I bought \(total) apples.")
Swift 5:
extension String {
var allNumbers: [Int] {
let numbersInString = self.components(separatedBy: .decimalDigits.inverted).filter { !$0.isEmpty }
return numbersInString.compactMap { Int($0) }
}
}
You can get all numbers like
var str = "I have to buy 3 apples, 7 bananas, 10eggs"
// numbers = [3, 7, 10]
numbers = str.allNumbers

Remove nth character from string

I have seen many methods for removing the last character from a string. Is there however a way to remove any old character based on its index?
Here is a safe Swift 4 implementation.
var s = "Hello, I must be going"
var n = 5
if let index = s.index(s.startIndex, offsetBy: n, limitedBy: s.endIndex) {
s.remove(at: index)
print(s) // prints "Hello I must be going"
} else {
print("\(n) is out of range")
}
While string indices aren't random-access and aren't numbers, you can advance them by a number in order to access the nth character:
var s = "Hello, I must be going"
s.removeAtIndex(advance(s.startIndex, 5))
println(s) // prints "Hello I must be going"
Of course, you should always check the string is at least 5 in length before doing this!
edit: as #MartinR points out, you can use the with-end-index version of advance to avoid the risk of running past the end:
let index = advance(s.startIndex, 5, s.endIndex)
if index != s.endIndex { s.removeAtIndex(index) }
As ever, optionals are your friend:
// find returns index of first match,
// as an optional with nil for no match
if let idx = s.characters.index(of:",") {
// this will only be executed if non-nil,
// idx will be the unwrapped result of find
s.removeAtIndex(idx)
}
Swift 3.2
let str = "hello"
let position = 2
let subStr = str.prefix(upTo: str.index(str.startIndex, offsetBy: position)) + str.suffix(from: str.index(str.startIndex, offsetBy: (position + 1)))
print(subStr)
"helo"
var hello = "hello world!"
Let's say we want to remove the "w". (It's at the 6th index position.)
First: Create an Index for that position. (I'm making the return type Index explicit; it's not required).
let index:Index = hello.startIndex.advancedBy(6)
Second: Call removeAtIndex() and pass it our just-made index. (Notice it returns the character in question)
let choppedChar:Character = hello.removeAtIndex(index)
print(hello) // prints hello orld!
print(choppedChar) // prints w

How to replace nth character of a string with another

How could I replace nth character of a String with another one?
func replace(myString:String, index:Int, newCharac:Character) -> String {
// Write correct code here
return modifiedString
}
For example, replace("House", 2, "r") should be equal to "Horse".
Solutions that use NSString methods will fail for any strings with multi-byte Unicode characters. Here are two Swift-native ways to approach the problem:
You can use the fact that a String is a sequence of Character to convert the string to an array, modify it, and convert the array back:
func replace(myString: String, _ index: Int, _ newChar: Character) -> String {
var chars = Array(myString) // gets an array of characters
chars[index] = newChar
let modifiedString = String(chars)
return modifiedString
}
replace("House", 2, "r")
// Horse
Alternately, you can step through the string yourself:
func replace(myString: String, _ index: Int, _ newChar: Character) -> String {
var modifiedString = String()
for (i, char) in myString.characters.enumerate() {
modifiedString += String((i == index) ? newChar : char)
}
return modifiedString
}
Since these stay entirely within Swift, they're both Unicode-safe:
replace("🏠🏡🏠🏡🏠", 2, "🐴")
// 🏠🏡🐴🏡🏠
In Swift 4 it's much easier.
let newString = oldString.prefix(n) + char + oldString.dropFirst(n + 1)
This is an example:
let oldString = "Hello, playground"
let newString = oldString.prefix(4) + "0" + oldString.dropFirst(5)
where the result is
Hell0, playground
The type of newString is Substring. Both prefix and dropFirst return Substring. Substring is a slice of a string, in other words, substrings are fast because you don't need to allocate memory for the content of the string, but the same storage space as the original string is used.
I've found this solution.
var string = "Cars"
let index = string.index(string.startIndex, offsetBy: 2)
string.replaceSubrange(index...index, with: "t")
print(string)
// Cats
Please see NateCook answer for more details
func replace(myString: String, _ index: Int, _ newChar: Character) -> String {
var chars = Array(myString.characters) // gets an array of characters
chars[index] = newChar
let modifiedString = String(chars)
return modifiedString
}
For Swift 5
func replace(myString: String, _ index: Int, _ newChar: Character) -> String {
var chars = Array(myString) // gets an array of characters
chars[index] = newChar
let modifiedString = String(chars)
return modifiedString
}
replace("House", 2, "r")
This is no longer valid and deprecated.
You can always use swift String with NSString.So you can call NSString function on swift String.
By old stringByReplacingCharactersInRange: you can do like this
var st :String = "House"
let abc = st.bridgeToObjectiveC().stringByReplacingCharactersInRange(NSMakeRange(2,1), withString:"r") //Will give Horse
For modify existing string:
extension String {
subscript(_ n: Int) -> Character {
get {
let idx = self.index(startIndex, offsetBy: n)
return self[idx]
}
set {
let idx = self.index(startIndex, offsetBy: n)
self.replaceSubrange(idx...idx, with: [newValue])
}
}
}
var s = "12345"
print(s[0])
s[0] = "9"
print(s)
I've expanded upon Nate Cooks answer and transformed it into a string extension.
extension String {
//Enables replacement of the character at a specified position within a string
func replace(_ index: Int, _ newChar: Character) -> String {
var chars = Array(characters)
chars[index] = newChar
let modifiedString = String(chars)
return modifiedString
}
}
usage:
let source = "House"
let result = source.replace(2,"r")
result is "Horse"
I think what #Greg was trying to achieve with his extension is this:
mutating func replace(characterAt index: Int, with newChar: Character) {
var chars = Array(characters)
if index >= 0 && index < self.characters.count {
chars[index] = newChar
let modifiedString = String(chars)
self = modifiedString
} else {
print("can't replace character, its' index out of range!")
}
}
usage:
let source = "House"
source.replace(characterAt: 2, with: "r") //gives you "Horse"
After looking at the Swift Docs, I managed to make this function:
//Main function
func replace(myString:String, index:Int, newCharac:Character) -> String {
//Looping through the characters in myString
var i = 0
for character in myString {
//Checking to see if the index of the character is the one we're looking for
if i == index {
//Found it! Now instead of adding it, add newCharac!
modifiedString += newCharac
} else {
modifiedString += character
}
i = i + 1
}
// Write correct code here
return modifiedString
}
Please note that this is untested, but it should give you the right idea.
func replace(myString:String, index:Int, newCharac:Character) -> String {
var modifiedString = myString
let range = Range<String.Index>(
start: advance(myString.startIndex, index),
end: advance(myString.startIndex, index + 1))
modifiedString.replaceRange(range, with: "\(newCharac)")
return modifiedString
}
I would prefer to pass a String than a Character though.
Here's a way to replace a single character:
var string = "This is the original string."
let offset = 27
let index = string.index(string.startIndex, offsetBy: offset)
let range = index...index
print("ORIGINAL string: " + string)
string.replaceSubrange(range, with: "!")
print("UPDATED string: " + string)
// ORIGINAL string: This is the original string.
// UPDATED string: This is the original string!
This works with multi-character strings as well:
var string = "This is the original string."
let offset = 7
let index = string.index(string.startIndex, offsetBy: offset)
let range = index...index
print("ORIGINAL string: " + string)
string.replaceSubrange(range, with: " NOT ")
print("UPDATED string: " + string)
// ORIGINAL string: This is the original string.
// UPDATED string: This is NOT the original string.
var s = "helloworld"
let index = ((s.count) / 2) // index is 4
let firstIndex = s.index(s.startIndex, offsetBy: index)
let secondIndex = s.index(s.startIndex, offsetBy: index)
s.replaceSubrange(firstIndex...secondIndex, with: "*")
print("Replaced string is: \(s)") //OUTPUT IS: hell*world
This is working fine to replace string using the index.
String class in Swift (till v5 and maybe later) is what other languages call a StringBuilder class, and for performance reasons, Swift does NOT provide setting character by index; If you don't care about performance a simple solution could be:
public static func replace(_ string: String, at index: Int, with value: String) {
let start = string.index(string.startIndex, offsetBy: index)
let end = string.index(start, offsetBy: 1)
string.replaceSubrange(start..<end, with: value)
}
Or as an extension:
extension String {
public func charAt(_ index: Int) -> Character {
return self[self.index(self.startIndex, offsetBy: index)];
}
public mutating func setCharAt(_ index: Int, _ new: Character) {
self.setCharAt(index, String(new))
}
public mutating func setCharAt(_ index: Int, _ new: String) {
let i = self.index(self.startIndex, offsetBy: index)
self.replaceSubrange(i...i, with: new)
}
}
Note how above needs to call index(...) method to convert integer to actual-index!? It seems, Swift implements String like a linked-list, where append(...) is really fast, but even finding the index (without doing anything with it) is a linear-time operation (and gets slower based on concatenation count).
public void createEncodedSentence() {
StringBuffer buff = new StringBuffer();
int counter = 0;
char a;
for (int i = 0; i < sentence.length(); i++) {
a = sentence.charAt(i);
if (a == '.') {
buff.append('*');
}
if (a != ' ' && a != '.') {
counter++;
}
if (counter % 3 == 0) {
buff.append("");
}
buff.append(sentence.charAt(i));
}
encodedSentence = buff.toString();
}
Strings in swift don't have an accessor to read or write a single character. There's an excellent blog post by Ole Begemann describing how strings in swift work.
Note: the implementation below is wrong, read addendum
So the right way is by taking the left part of the string up to the index -1 character, append the replacing character, then append the string from index + 1 up to the end:
func myReplace(myString:String, index:Int, newCharac:Character) -> String {
var modifiedString: String
let len = countElements(myString)
if (index < len) && (index >= 0) {
modifiedString = myString.substringToIndex(index) + newCharac + myString.substringFromIndex(index + 1)
} else {
modifiedString = myString
}
return modifiedString
}
Note: in my implementation I chose to return the original string if the index is not in a valid range
Addendum Thanks to #slazyk, who found out that my implementation is wrong (see comment), I am providing a new swift only version of the function.
func replace(myString:String, index:Int, newCharac:Character) -> String {
var modifiedString: String
if (index < 0) || (index >= countElements(myString)) {
modifiedString = myString
} else {
var start = myString.startIndex
var end = advance(start, index)
modifiedString = myString[start ..< end]
modifiedString += newCharac
start = end.successor()
end = myString.endIndex
modifiedString += myString[start ... end]
}
return modifiedString
}
#codester's answer looks very good, and it's probably what I would use myself.
It would be interesting to know how performances compare though, using a fully swift solution and bridging to objective-c instead.
Here is an efficient answer :
import Foundation
func replace(myString:String, index:Int, newCharac:Character) -> String {
return myString.substringToIndex(index-1) + newCharac + myString.substringFromIndex(index)
}

Resources