计算Swift中正则表达式的最小匹配长度

时间:2016-06-12 17:50:04

标签: regex swift algorithm

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

φ(r)=Int

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

的内容

φ(\bimport\s+)=7

而不是必须手动标记"最小模式长度"每个正则表达式的元数据片段。在我去之前的任何想法尝试重新创建一个看似非常复杂的轮子,我自己?尽管如此,我还是会喜欢这个挑战。我认为我必须使用正则表达式来分析正则表达式本身。在此先感谢您的帮助!我正在寻找用Swift编写的解决方案,但通用版本不会受到伤害。

3 个答案:

答案 0 :(得分: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的正则表达式具有递归功能,则此任务变得更加困难。

要记住的另一件事是,一些正则表达式可能永远不会匹配任何东西(但是这可能很难解决),并且“最小匹配长度”在这些情况下毫无意义。

答案 1 :(得分:0)

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

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

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

如果您只希望它可以在regexp语言的一小部分上工作,那么您可以非常轻松地编写一个更简单的此工具版本。但是,根据经验,创建一个通用的解决方案"这样很复杂。

答案 2 :(得分:0)

这是一项正在进行的工作,但这是我到目前为止所做的......

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

    }

}