4 Replies
      Latest reply: Oct 9, 2016 9:04 AM by eskimo RSS
      Albinus Level 1 Level 1 (0 points)

        This is what I've been doing to change a single letter at a specific location in a word:

         

        let word = "abc"
        var letters = Array(word.characters)
        letters[1] = "x"
        let newWord = String(letters)
        
        

         

        Surely there's a more elegant way in Swift 3. But is this really it?

         

        let index = word.index(word.startIndex, offsetBy: 1)
        let range = index ..< word.index(after: index)
        word.replacingCharacters(in: range, with: "x")
        

         

        It works; but it looks hideous.

        • Re: Changing a character in String
          OOPer Level 7 Level 7 (3,345 points)

          This code does not generate intermediate Array of Characters.

          let word = "abc"
          let index = word.index(word.startIndex, offsetBy: 1)
          let newWord = word.replacingCharacters(in: index..<word.index(after: index), with: "x")
          

          or

          var mutableWord = "abc"
          let index = mutableWord.index(mutableWord.startIndex, offsetBy: 1)
          mutableWord.replaceSubrange(index..<mutableWord.index(after: index), with: "x")
          

           

          But, in my oponion, this is far from elegant. Maybe we should wait until Swift 4 to get some elegant String APIs...

            • Re: Changing a character in String
              Albinus Level 1 Level 1 (0 points)

              You must have posted this at the same time I added my second code example. So maybe that is the best way. But I certainly agree that it's far from elegant. Perhaps something can be done with an extension.

                • Re: Changing a character in String
                  OOPer Level 7 Level 7 (3,345 points)

                  Sorry, when you added your second code, I may have been struggling with the Playground which demanded so many restarts, and I posted my article without knowing the update.

                   

                  Writing such sort of extension is not a difficult thing:

                  var mutableWord = "abc"
                  extension String {
                      subscript (at offset: Int)->Character {
                          get {
                              let index = self.index(self.startIndex, offsetBy: offset)
                              return self.characters[index]
                          }
                          mutating set {
                              let index = self.index(self.startIndex, offsetBy: offset)
                              self.replaceSubrange(index...index, with: String(newValue))
                          }
                      }
                  }
                  mutableWord[at: 1] = "y"
                  print(mutableWord) //->ayc
                  

                   

                  One bad thing is this is not a standard.

                   

                  Chris Lattner stated that String re-evaluation is one of the Swift 4 Stage 1 Goals:

                  - String re-evaluation: String is one of the most important fundamental types in the language.  The standard library leads have numerous ideas of how to improve the programming model for it, without jeopardizing the goals of providing a unicode-correct-by-default model.  Our goal is to be better at string processing than Perl!

                  (You can find this in the ML archive of swift-evolution-announce.)

                   

                  I really expect better-than-Perl String APIs, and have decided not to make much private extensions.

              • Re: Changing a character in String
                eskimo Apple Staff Apple Staff (6,310 points)

                This is what I've been doing to change a single letter at a specific location in a word …

                Where did you get that location?  That is, in your example, where did the 1 come from?

                The reason I ask is that numeric indexes like that rarely make sense in the general case of Unicode strings.  For example, if you change the input of your original code to use a skin toned emoji, it’s results are less than ideal.

                let word = "\u{1F466}\u{1F3FE}bc"
                var letters = Array(word.characters) 
                letters[1] = "x" 
                let newWord = String(letters)      // "\u{1F466}xbc"
                

                What you do about this depends on the constraints that you can apply to your strings.  For example, if you knew that word was ASCII (it’s a string from an HTTP header, say) then you can ignore Unicode and treat it like an array of UInt8.  OTOH, if word is derived from user text, you’ll need to rethink your approach.

                Share and Enjoy

                Quinn “The Eskimo!”
                Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                let myEmail = "eskimo" + "1" + "@apple.com"