Swift replace substring regex

50,615

Solution 1

You need to remove the ^ and $ anchors.

The ^ means start of string and $ means end of string (or line, depending on the options). That's why your first example works: in the first test string, the start of the string is really followed by your pattern and ends with it.

In the second test string, the pattern is found in the middle of the string, thus the ^... can't apply. If you would just remove the ^, the $ would apply on the second occurrence of the registration number and the output would be my car reg 1 - DD11 AAA my car reg 2 - XX.

let myString = "my car reg 1 - DD11 AAA  my car reg 2 - AA22 BBB"
let regex = try! NSRegularExpression(pattern: "([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}", options: NSRegularExpression.Options.caseInsensitive)
let range = NSMakeRange(0, myString.count)
let modString = regex.stringByReplacingMatches(in: myString, options: [], range: range, withTemplate: "XX")
print(modString)
// Output: "my car reg 1 - XX  my car reg 2 - XX"

Solution 2

Let's use a class extension to wrap this up in Swift 3 syntax:

extension String {
    mutating func removingRegexMatches(pattern: String, replaceWith: String = "") {
        do {
            let regex = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)
            let range = NSRange(location: 0, length: count)
            self = regex.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: replaceWith)
        } catch { return }
    }
}

var phoneNumber = "+1 07777777777"
phoneNumber.removingRegexMatches(pattern: "\\+\\d{1,4} (0)?")

Results in 7777777777 (thus removing country code from phone number)

Solution 3

Swift 4.2 Updated

let myString = "my car reg 1 - DD11 AAA  my car reg 2 - AA22 BBB"
if let regex = try? NSRegularExpression(pattern: "([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}", options: .caseInsensitive) {
    let modString = regex.stringByReplacingMatches(in: myString, options: [], range: NSRange(location: 0, length:  myString.count), withTemplate: "XX")
    print(modString)
}

Solution 4

Update for Swift 2.1:

var myString = "my car reg 1 - DD11 AAA  my car reg 2 - AA22 BBB"
if let regex = try? NSRegularExpression(pattern: "([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}", options: .CaseInsensitive) {
    let modString = regex.stringByReplacingMatchesInString(myString, options: .WithTransparentBounds, range: NSMakeRange(0, myString.characters.count), withTemplate: "XX")
    print(modString)
}

Solution 5

Warning

Do not use NSRange(location: 0, length: myString.count) as all examples above quoted.

Use NSRange(myString.startIndex..., in: myString) instead!

.count will count newline characters like \r\n as one character - this may result in a shortened, thus invalid, NSRange that does not match the whole string.

(.length should work)

Share:
50,615
jjc99
Author by

jjc99

Updated on July 09, 2022

Comments

  • jjc99
    jjc99 almost 2 years

    I am attempting to use regular expression to replace all occurrences of UK car registrations within a string.

    The following swift code works perfectly for a when the string matches the regex exactly as below.

    var myString = "DD11 AAA"
    var stringlength = countElements(myString) 
    var ierror: NSError?
    var regex:NSRegularExpression = NSRegularExpression(pattern: "^([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}$", options: NSRegularExpressionOptions.CaseInsensitive, error: &ierror)!
    var modString = regex.stringByReplacingMatchesInString(myString, options: nil, range: NSMakeRange(0, stringlength), withTemplate: "XX")
    print(modString)
    

    The result is XX

    However, the following does not work and the string is not modifed

    var myString = "my car reg 1 - DD11 AAA  my car reg 2 - AA22 BBB"
    var stringlength = countElements(myString) 
    var ierror: NSError?
    var regex:NSRegularExpression = NSRegularExpression(pattern: "^([A-HK-PRSVWY][A-HJ-PR-Y])\\s?([0][2-9]|[1-9][0-9])\\s?[A-HJ-PR-Z]{3}$", options: NSRegularExpressionOptions.CaseInsensitive, error: &ierror)!
    var modString = regex.stringByReplacingMatchesInString(myString, options: nil, range: NSMakeRange(0, stringlength), withTemplate: "XX")
    print(modString)
    

    The result is my car reg 1 - DD11 AAA my car reg 2 - AA22 BBB

    Can anyone give me any pointers?

  • onmyway133
    onmyway133 about 8 years
    the option that DarkDust mention is AnchorsMatchLines
  • xxmbabanexx
    xxmbabanexx about 7 years
    for some reason NSRegularExpression doesn't seem to be working in swift 3. How would you go about correcting this?
  • ablarg
    ablarg over 6 years
    use of NSMakeRange generates warning: Legacy Constructor Violation: Swift constructors are preferred over legacy convenience functions. (legacy_constructor) in swiftlint
  • Constantine
    Constantine almost 4 years
    @ablarg you can fix that by replacing the line with: let range = NSRange(location: 0, length: self.count)