【问题标题】:Swift replace substring regexSwift 替换子字符串正则表达式
【发布时间】:2015-02-13 15:51:53
【问题描述】:

我正在尝试使用正则表达式替换字符串中所有出现的英国汽车注册。

当字符串与正则表达式完全匹配时,以下 swift 代码非常适用。

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)

结果是XX

但是,以下不起作用并且字符串没有被修改

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)

结果是my car reg 1 - DD11 AAA my car reg 2 - AA22 BBB

谁能给我指点?

【问题讨论】:

    标签: ios objective-c regex xcode swift


    【解决方案1】:

    您需要删除 ^$ 锚点。

    ^ 表示 字符串开头$ 表示 字符串结尾(或行,取决于选项)。这就是您的第一个示例有效的原因:在第一个测试字符串中,字符串的开头实际上是您的模式并以它结束。

    在第二个测试字符串中,模式位于字符串中间,因此^... 无法应用。如果您只删除^$ 将适用于第二次出现的注册号,输出将为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"
    

    【讨论】:

    • DarkDust 提到的选项是AnchorsMatchLines
    • 由于某种原因 NSRegularExpression 似乎无法在 swift 3 中运行。您将如何解决这个问题?
    【解决方案2】:

    让我们使用一个类扩展来用 Swift 3 语法把它包装起来:

    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)?")
    

    7777777777 的结果(从而从电话号码中删除国家代码)

    【讨论】:

    • 使用 NSMakeRange 在 swiftlint 中生成 warning: Legacy Constructor Violation: Swift constructors are preferred over legacy convenience functions. (legacy_constructor)
    • @alarge 您可以通过将行替换为:let range = NSRange(location: 0, length: self.count) 来解决此问题
    【解决方案3】:

    Swift 4.2 更新

    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)
    }
    

    【讨论】:

      【解决方案4】:

      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)
      }
      

      【讨论】:

        【解决方案5】:

        警告

        不要像上面引用的所有示例一样使用NSRange(location: 0, length: myString.count)

        改用NSRange(myString.startIndex..., in: myString)

        .count 将像 \r\n 这样的换行符计为一个字符 - 这可能会导致 NSRange 缩短,因此无效,与整个字符串不匹配。

        (.length 应该可以)

        【讨论】:

          【解决方案6】:

          使用pattern: "^ ... $",您已指定模式已锚定 到字符串的开头和结尾,换句话说,整个字符串 必须匹配模式。只需从模式中删除 ^$ 你会得到预期的结果。

          【讨论】:

            【解决方案7】:

            简单的扩展:

            extension String {
            
                func replacingRegex(
                    matching pattern: String,
                    findingOptions: NSRegularExpression.Options = .caseInsensitive,
                    replacingOptions: NSRegularExpression.MatchingOptions = [],
                    with template: String
                ) throws -> String {
            
                    let regex = try NSRegularExpression(pattern: pattern, options: findingOptions)
                    let range = NSRange(startIndex..., in: self)
                    return regex.stringByReplacingMatches(in: self, options: replacingOptions, range: range, withTemplate: template)
                }
            

            ✅其他答案的优势

            • error 暴露给调用者
            • 为了便于使用,默认向调用者公开了查找选项
            • 为调用者提供默认替换选项以方便使用
            • 修复了原答案中的rangeBUG?

            【讨论】:

              【解决方案8】:

              所有在答案中使用.count 的答案的通知:

              如果操作目标范围具有代理配对字符,这将导致问题。

              请改用.utf16.count 来修正您的答案。

              这是 Ryan Brodie 对此修复的回答。它适用于 Swift 5.5。

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

              更新:如果考虑到@coyer 的担忧:

              private extension String {
                  mutating func regReplace(pattern: String, replaceWith: String = "") {
                      do {
                          let regex = try NSRegularExpression(pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines])
                          let range = NSRange(self.startIndex..., in: self)
                          self = regex.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: replaceWith)
                      } catch { return }
                  }
              }
              

              另外: 致@Martin R': 只要您在 Regex 选项中启用了“.anchorsMatchLines”,就可以在 Regex 中使用 ^ 和 $。我已经在上面的代码块中应用了这个选项。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2019-04-17
                • 1970-01-01
                • 2018-07-13
                • 1970-01-01
                • 1970-01-01
                • 2017-02-04
                相关资源
                最近更新 更多