'how can I edit lots of swift string at once?

In my project, I have Localizable.string file which is having more than 10,000 lines keyValue format. I need to convert all of keys which are dotCase format like "contentsList.sort.viewCount" to lowerCamelCase. how can I convert by using swift scripting? thank you.

as-is

"contentsList.horizontal.more" = "totall";

to-be

"contentsListHorizontalMore" = "totall";


Solution 1:[1]

First get all lines from your string. CompactMap your lines breaking it up into two components separated by the equal sign. Get the first component otherwise return nil. Get all ranges of the regex (\w)\.(\w). Replace the match range by the first + second group capitalized. This will remove the period. Return a collection of one element (snake case) + the other components joined by the separator equal sign. Now that you have all lines you just need to join them by the new line character:


let string = """
"contentsList.horizontal.more" = "totall";

"whatever.vertical.less" = "summ";
"""

let pattern = #"(\w)\.(\w)"#
let lines = string.split(omittingEmptySubsequences: false,
                         whereSeparator: \.isNewline)
let result: [String] = lines.compactMap {
    let comps = $0.components(separatedBy: " = ")
    guard var first = comps.first else { return nil }
    let regex = try! NSRegularExpression(pattern: pattern)
    let matches = regex.matches(in: first, range: NSRange(first.startIndex..., in: first))
    let allRanges: [[Range<String.Index>]] = matches.map { match in
        (0..<match.numberOfRanges).compactMap { (index: Int) -> Range<String.Index>? in
            Range(match.range(at: index), in: first)
        }
    }
    for ranges in allRanges.reversed() {
        first.replaceSubrange(ranges[0], with: first[ranges[1]] + first[ranges[2]].uppercased())
    }
    return (CollectionOfOne(first) + comps.dropFirst())
        .joined(separator: " = ")
}
let finalString = result.joined(separator: "\n")
print(finalString)

This will print

"contentsListHorizontalMore" = "totall";

"whateverVerticalLess" = "summ";

Solution 2:[2]

You could subclass NSRegularExpression and override replacementString to be able to modify the string represented by the template parameter.

class CapitalizeRegex: NSRegularExpression {
    override func replacementString(for result: NSTextCheckingResult, in string: String, offset: Int, template templ: String) -> String {
        guard result.numberOfRanges == 2,
              let range = Range(result.range(at: 1), in: string) else { return "" }
        return string[range].capitalized
    }
} 

Then search for a dot followed by a word and capture the latter. The $1 pattern will capitalize the word

let string = #"contentsList.horizontal.more" = "totall";"#

let regex = try! CapitalizeRegex(pattern: #"\.(\b\w+\b)"#)
let result = regex.stringByReplacingMatches(in: string,
                                            range: NSRange(string.startIndex..., in: string),
                                            withTemplate: "$1")
print(result)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2