2

I was trying to change hello_world to helloWorld by this snippet of code (Swift 3.0):

import Foundation

let oldLine = "hello_world"
let fullRange = NSRange(location: 0, length: oldLine.characters.count)
let newLine = NSMutableString(string: oldLine)

let regex = try! NSRegularExpression(pattern: "(_)(\\w)", options: [])
regex.replaceMatches(in: newLine, options: [], range: fullRange, 
    withTemplate: "\\L$2")

The result was newLine = "helloLworld"

I used "\\L$2" as template because I saw this answer: https://stackoverflow.com/a/20742304/5282792 saying \L$2 is the pattern for the second group's uppercase in replacement template. But it didn't work in NSRegularExpression.

So can I replace a string with its uppercase with a replacement template pattern in NSRegularExpression.

Community
  • 1
  • 1
Shane Qi
  • 115
  • 2
  • 8
  • SublimeText uses Boost regex that supports `\L` operator. Swift uses ICU, it does not support case chahging operators. – Wiktor Stribiżew Oct 28 '16 at 05:52
  • @WiktorStribiżew So `NSRegularExpression` supports nothing other than `$num` in replacement template? – Shane Qi Oct 28 '16 at 05:53
  • A backslash is also a special char in ICU regex replacement patterns, see [*ICU User Guide: Replacement Text*](http://www.icu-project.org/userguide/regexp). – Wiktor Stribiżew Oct 28 '16 at 05:56
  • Are you set on using a RegEx for this? I could give you some code using methods on `String` that would do what you want nicely. – Jacob King Oct 28 '16 at 06:59

2 Answers2

1

One way to work with your case is subclassing NSRegularExpression and override replacementString(for:in:offset:template:) method.

class ToUpperRegex: NSRegularExpression {
    override func replacementString(for result: NSTextCheckingResult, in string: String, offset: Int, template templ: String) -> String {
        guard result.numberOfRanges > 2 else {
            return ""
        }
        let matchingString = (string as NSString).substring(with: result.rangeAt(2)) as String
        return matchingString.uppercased()
    }
}

let oldLine = "hello_world"
let fullRange = NSRange(0..<oldLine.utf16.count) //<-
let tuRegex = try! ToUpperRegex(pattern: "(_)(\\w)")
let newLine = tuRegex.stringByReplacingMatches(in: oldLine, range: fullRange, withTemplate: "")
print(newLine) //->helloWorld
OOPer
  • 47,149
  • 6
  • 107
  • 142
0

This doesn't answer the question pertaining regex, but might be of interest for readers not necessarily needing to use regex to perform this task (rather, using native Swift)

extension String {
    func camelCased(givenSeparators separators: [Character]) -> String {
        let charChunks = characters.split { separators.contains($0) }
        guard let firstChunk = charChunks.first else { return self }
        return String(firstChunk).lowercased() + charChunks.dropFirst()
            .map { String($0).onlyFirstCharacterUppercased }.joined()
    }

    // helper (uppercase first char, lowercase rest)
    var onlyFirstCharacterUppercased: String {
        let chars = characters
        guard let firstChar = chars.first else { return self }
        return String(firstChar).uppercased() + String(chars.dropFirst()).lowercased()
    }
}

/* Example usage */
let oldLine1 = "hello_world"
let oldLine2 = "fOo_baR BAX BaZ_fOX"

print(oldLine1.camelCased(givenSeparators: ["_"]))      // helloWorld
print(oldLine2.camelCased(givenSeparators: ["_", " "])) // fooBarBazBazFox
dfrib
  • 70,367
  • 12
  • 127
  • 192