Piercy
Piercy

Reputation: 493

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".

Upvotes: 38

Views: 41094

Answers (16)

VicSF
VicSF

Reputation: 31

To 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) 

Upvotes: 3

Kishlay Kishore
Kishlay Kishore

Reputation: 11

/* Replace Every Nth charater in String with another character*/

    func replaceAllNthChar(inputString:String, nthChar: Int, replaceBy:Character) -> String {
    var arrStr = Array(inputString)
    let n = nthChar
    
    for i in stride(from: (n - 1), to: arrStr.count - 1, by: n) {
        arrStr[i] = replaceBy
    }
    return String(arrStr)
}

print(replaceNthChar(inputString: "abcdefghijklmop", nthChar: 4, replaceBy: "_"))

Upvotes: 0

Pramuditha
Pramuditha

Reputation: 1

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();

}

Upvotes: 0

Top-Master
Top-Master

Reputation: 8796

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).

Upvotes: 0

Priyanka Gayathri
Priyanka Gayathri

Reputation: 1

        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.

Upvotes: 0

codester
codester

Reputation: 37189

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

Upvotes: 8

Kwan McComas
Kwan McComas

Reputation: 11

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.

Upvotes: 0

Nate Cook
Nate Cook

Reputation: 93286

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, "🐴")
// 🏠🏑🐴🏑🏠

Upvotes: 38

Luca Torella
Luca Torella

Reputation: 8214

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.

Upvotes: 22

Yurii Koval
Yurii Koval

Reputation: 429

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"

Upvotes: 1

Greg
Greg

Reputation: 525

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"

Upvotes: 1

Igor Kulagin
Igor Kulagin

Reputation: 1771

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

Upvotes: 23

E. Rivera
E. Rivera

Reputation: 10938

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.

Upvotes: 0

Piercy
Piercy

Reputation: 493

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)
}

Upvotes: -1

Antonio
Antonio

Reputation: 72760

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.

Upvotes: -1

Joshcamas
Joshcamas

Reputation: 31

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.

Upvotes: 0

Related Questions