RegExp result is not my expected

205 views Asked by At

My regExp do not get a correct result, I can not find where is mistake.

    let ori_str = "abcXabcYabcZ"  // there are 3 Capital character

    let pattern = "[A-Z]"

    let regular = try!NSRegularExpression(pattern: pattern, options: .caseInsensitive)

    let results = regular.matches(in: ori_str, options: .reportProgress , range: NSMakeRange(0, ori_str.characters.count))
    print("results have: \(results.count) count")  // log  'result have: 12 count'  why 12 without 3 ???

I want to get the Capital Character, then replace them to -(the Capital character's lower character)-, but my regExp's result is console 12 count of Capital Characters.

1) You see, it should be 3, where is the mistake ?
2) How to replace the Capital character to -(the capital's lower character)- ?


Addition -1

There are all of the NSRegularExpression.Options below:

    public static var caseInsensitive: NSRegularExpression.Options { get }

    public static var allowCommentsAndWhitespace: NSRegularExpression.Options { get }

    public static var ignoreMetacharacters: NSRegularExpression.Options { get }

    public static var dotMatchesLineSeparators: NSRegularExpression.Options { get }

    public static var anchorsMatchLines: NSRegularExpression.Options { get }

    public static var useUnixLineSeparators: NSRegularExpression.Options { get }

    public static var useUnicodeWordBoundaries: NSRegularExpression.Options { get }`
1

There are 1 answers

2
kevin On BEST ANSWER

You need to do a case-sensitive match. Change options from .caseInsensitive to [].

NSRegularExpression.Options is an OptionSet, which allows specifying zero or more values. When passing zero, or more then one, an array literal syntax is used. See: https://developer.apple.com/reference/swift/optionset

let ori_str = "abcXabcYabcZ"  // there are 3 Capital character
let pattern = "[A-Z]"
let regular = try!NSRegularExpression(pattern: pattern, options: [])
let results = regular.matches(in: ori_str, options: .reportProgress, range: NSMakeRange(0, ori_str.characters.count))
print("results have: \(results.count) count")

Regarding your second criteria, using a regex group will cover that:

let ori_str = "abcXabcYabcZ"  // there are 3 Capital character
let pattern = "([A-Z])"
let regular = try!NSRegularExpression(pattern: pattern)
let replaced = regular.stringByReplacingMatches(
    in: ori_str, options: [],
    range: NSMakeRange(0, ori_str.characters.count),
    withTemplate: "-$1-").lowercased()
print("Uppercase characters replaced: \(replaced)")

For something more advanced, where you need additional custom code for each match:

extension String {
    func replace(regex: NSRegularExpression, with replacer: (_ match:String)->String) -> String {
        let str = self as NSString
        let ret = str.mutableCopy() as! NSMutableString

        let matches = regex.matches(in: str as String, options: [], range: NSMakeRange(0, str.length))
        for match in matches.reversed() {
            let original = str.substring(with: match.range)
            let replacement = replacer(original)
            ret.replaceCharacters(in: match.range, with: replacement)
        }
        return ret as String
    }
}

let ori_str = "abcXabcYabcZ"  // there are 3 Capital character
let pattern = "[A-Z]"
let regular = try!NSRegularExpression(pattern: pattern)
let replaced = ori_str.replace(regex: regular) { "-\($0.lowercased())-" }
print("Uppercase characters replaced: \(replaced)")