【问题标题】:Calculate the Minimum Match Length of a Regular Expression in Swift在 Swift 中计算正则表达式的最小匹配长度
【发布时间】:2016-06-12 17:50:03
【问题描述】:

我想知道是否有人有算法来计算以字符串表示的给定正则表达式的最小可能匹配长度。例如,让我们调用这个算法

其中 是正则表达式,函数输出一个整数值。我想在我的应用程序中使用这个算法,所以我可以计算出类似

而不必为每个正则表达式手动标记“最小模式长度”元数据。在我去尝试重新创建一个看起来非常复杂的轮子之前有什么想法吗?尽管如此,我还是会享受挑战的。我想我将不得不使用正则表达式来分析正则表达式本身。在此先感谢您的帮助!我正在寻找用 Swift 编写的解决方案,但通用版本不会受到伤害。

【问题讨论】:

    标签: regex swift algorithm


    【解决方案1】:

    你想做的事情需要一些工作。您将需要开发自己的正则表达式解析器,我不会为您这样做(我不知道 Swift,但不应该只使用正则表达式来完成正确的解析器)。不过,我可以帮助算法。

    我认为这项工作的方式是逐步删除和更改正则表达式,直到可以得到具体答案。显然,您不应该在您唯一的正则表达式副本上执行此操作,因为这可能最终会破坏正则表达式。

    这里有一些步骤:

    • . 替换char 类。您需要注意了解 Swift 的正则表达式如何处理奇怪的语法,例如 [],在某些情况下,它会将 ] 视为文字,否则语法将无效。
    • 删除最大值:(regex part){min,max}
      • (regex part){min} 替换为min 重复的regex part
    • 删除* 语句:(regex part)*
    • 删除任何+ 符号:(regex part)+
    • 对于交替,找到最短的交替,并删除所有其他的:(regex part is long|but this regex part is super duper long|medium regex|short)
    • 将 char 类替换为 .
    • 将所有转义文字替换为.,甚至\n。请记住,放弃花哨的语法会更容易计算最少的字符数。

    这不是一个详尽的列表,但希望它可以帮助您入门。需要注意的是抢先删除括号,这可能会弄乱操作顺序和反向引用。如果 Swift 的正则表达式具有递归功能,那么这项任务就会变得更加困难。

    要记住的另一件事是,某些正则表达式可能永远不会匹配任何内容(但弄清楚这一点可能很困难),在这些情况下,“最小匹配长度”毫无意义。

    【讨论】:

    • 非常感谢这些提示。是的,这需要大量的理论知识,只需将表达式缩减为一个短字符串并返回该长度
    【解决方案2】:

    这是用 Ruby 编写的,而不是 Swift,但 here 是我编写的一个工具,可以用来解决问题:

    /import\s+/.examples.map(&:length).min # => 7
    

    此工具适用于所有正则表达式,除了包含环视的那些。 (前瞻、后瞻、词边界锚等)

    如果您只希望它在 regexp 语言的一小部分上工作,您可以很容易地自己编写这个工具的一个更简单的版本。但是,从经验来看,创建这样的“通用解决方案”非常复杂。

    【讨论】:

      【解决方案3】:

      这是一项正在进行的工作,但这是我目前所拥有的......

      public extension String {
      
          public var minRegexMatchLength: Int {
      
              let pattern = (self as NSString).mutableCopy() as! NSMutableString
      
              if let expr = try? NSRegularExpression(pattern: "((\\(.*?\\))|(\\[.*?\\])|.)[*?]", options: []) {
                  expr.replaceMatchesInString(pattern, options: [], range: NSMakeRange(0, (pattern as String).length), withTemplate: "")
              }
      
              if let expr = try? NSRegularExpression(pattern: "((\\(.*?\\))|(\\[.*?\\])|.)[+]", options: []) {
                  expr.replaceMatchesInString(pattern, options: [], range: NSMakeRange(0, (pattern as String).length), withTemplate: ".")
              }
      
              if let expr = try? NSRegularExpression(pattern: "(\\[bswBSW])", options: []) {
                  expr.replaceMatchesInString(pattern, options: [], range: NSMakeRange(0, (pattern as String).length), withTemplate: ".")
              }
      
              if let expr = try? NSRegularExpression(pattern: "\\(.*?\\)", options: []) {
      
                  var lengths = [Int]()
      
                  expr.enumerateMatchesInString(pattern as String, options: [], range: NSMakeRange(0, (pattern as String).length)) 
                  { (result: NSTextCheckingResult?, _, _) -> Void in
                      if let result = result {
                          let substring = pattern.substringWithRange(NSMakeRange(result.range.location + 1, result.range.length - 2))
                          var length = substring.length
                          for word in substring.componentsSeparatedByString("|") {
                              if (word.length < length) {
                                  length = word.length
                              }
                          }
                          lengths.append(length)
                      }
                  }
      
                  var match = expr.firstMatchInString(pattern as String, options: [], range: NSMakeRange(0, (pattern as String).length))
                  var i = 0
                  while match != nil && i < lengths.count {
                      if let range = match?.range {
                          pattern.replaceCharactersInRange(range, withString: "".stringByPaddingToLength(lengths[i], withString: ".", startingAtIndex: 0))
                      }
                      match = expr.firstMatchInString(pattern as String, options: [], range: NSMakeRange(0, (pattern as String).length))
                      i += 1
                  }
      
              }
      
              return pattern.length
      
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-06
        • 1970-01-01
        • 2021-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多