你怎么知道两个通配符是否重叠?

时间:2010-05-12 18:05:38

标签: algorithm language-agnostic string string-comparison

给定两个带*通配符的字符串,我想知道是否可以创建一个匹配两者的字符串。

例如,这两个是重叠的简单情况:

  1. 你好*世界
  2. 赫尔*
  3. 但所有这些都是如此:

    1. *。CSV
    2. 报告*的.csv
    3. reportsdump.csv
    4. 是否发布了执行此操作的算法?或者可能是Windows中的实用程序功能或者我可以调用或复制的库?

5 个答案:

答案 0 :(得分:6)

因为每个glob都可以写成正则表达式并且可以找到两个正则表达式的交集(除非它们不是真正的常规,但它们就是这种情况),你可以找到两个globs的交集。将它们转换为正则表达式,然后找到它们的交集。因此,您可以通过查找正则表达式的交集并检查它是否为空来查明两个globs是否相交。

然而,由于globs比正则表达式更受限制,因此更多更容易:

让我们调用两个球体g1和g2。它们与iff

相交
  1. g1和g2都为空或仅包含通配符。
  2. g1和g2都不为空且以下条件之一为真(让c1为g1的第一个字符,t1为包含剩余字符的字符串 - 对于g2与c2和t2相同):
    1. c1和c2相等,t1和t2相交
    2. c1和/或c2是通配符,t1与g2
    3. 相交
    4. c1和/或c2是通配符,g1与t2
    5. 相交
  3. haskell中的示例实现:

    intersect g1          []          = all (== '*') g1
    intersect []          g2          = all (== '*') g2
    intersect g1@('*':t1) g2@(c2:t2)  = intersect g1 t2 || intersect t1 g2
    intersect g1@(c1:t1)  g2@('*':t2) = intersect t1 g2 || intersect g1 t2
    intersect    (c1:t1)     (c2:t2)  = c1 == c2        && intersect t1 t2
    

    如果globs包含很多通配符,这个算法并不是特别有效,但它很容易实现,因为你可能计划将它与文件名一起使用,我怀疑你的globs会超过1000个字符。

答案 1 :(得分:0)

对于它的价值,这里是来自sepp2k在C#中的答案的一个算法实现(我使用显式return true;return false;调用,以及注释,用于算法可读性):

public static bool WildcardIntersect(string w1, string w2)
{
    // if both are empty or contain wildcards
    if ((string.IsNullOrEmpty(w1) || w1 == "*")
        && (string.IsNullOrEmpty(w2) || w2 == "*"))
        return true;

    // if either string is empty, return false
    // we can do this because we know the other string MUST be non-empty and non-wildcard
    if (string.IsNullOrEmpty(w1) || string.IsNullOrEmpty(w2))
        return false;

    char c1 = w1[0], // first character of wildcard string 1
         c2 = w2[0]; // first character of wildcard string 2
    string remain1 = w1.Substring(1), // remaining of wildcard string 1
           remain2 = w2.Substring(1); // remaining of wildcard string 2

    // if first letters match and remaining intersect
    if ((c1 == c2 && WildcardIntersect(remain1, remain2))
        // if either is a wildcard and either remaining intersects with the other whole
        || ((c1 == '*' || c2 == '*') && (WildcardIntersect(w1, remain2) || WildcardIntersect(remain1, w2))))
        return true;

    // else, no match, return false
    return false;
}

答案 2 :(得分:0)

据我所知,你试着确定正则表达式是否与另一个正则表达式正交? 如果是这样,这不是一件小事。

以下是Theory.

的更多信息

以下是解决方案:Java library.

用法:

/**
 * @return true if the two regexes will never both match a given string
 */
public boolean isRegexOrthogonal( String regex1, String regex2 ) {
   Automaton automaton1 = new RegExp(regex1).toAutomaton();
   Automaton automaton2 = new RegExp(regex2).toAutomaton();
   return automaton1.intersection(automaton2).isEmpty();
}

答案 3 :(得分:0)

这是sepp2k建议的算法的c ++实现,稍作修改:

bool intersect(const std::string& pattern1, const std::string& pattern2) {
    if(pattern1.empty() && pattern2.empty()) return true;
    if("*" == pattern1 || "*" == pattern2) return true;

    if(pattern2.empty() && '*' == pattern1[0]) return true;
    if(pattern1.empty() && '*' == pattern2[0]) return true;

    if(pattern1.empty() || pattern2.empty()) return false;

    char c1 = pattern1[0];
    char c2 = pattern2[0];
    string subPattern1 = pattern1.substr(1);
    string subPattern2 = pattern2.substr(1);


    if('*' == c1 && '*' == c2)
        return intersect(pattern1, subPattern2) && intersect(subPattern1, pattern2);

    if('*' == c1 && intersect(pattern1, subPattern2)
       || '*' == c2 && intersect(subPattern1, pattern2)
       || c1 == c2 && intersect(subPattern1, subPattern2)) {
        return true;
    }

    return false;
}

答案 4 :(得分:0)

您可以在时间上线性解决图案长度的总和:

如果两个字符串都以非通配符开头或结尾,请检查它们是否匹配,直到一个模式命中了通配符(否则它们不匹配)。这将问题减少到至少一个模式以通配符开始并且至少一个模式以通配符结束的情况。如果两个模式都有通配符(在某处),则它们必须匹配:

  • 如果p1以通配符开头,p2以通配符结尾,请使用p1 通配符吃掉所有p2直到最后一个通配符,然后使用p2 通配符吃掉所有p1
  • 如果p1以通配符开头和结尾,请使用其起始通配符 在第一个通配符之前吃掉p2,然后使用p2通配符 吃掉最后一个通配符的p1,然后使用最后一个p1通配符吃 剩下的p2

否则,一个字符串(p1)没有通配符,而另一个字符串(p2)具有字符串s1,s2,...以通配符标点。因此,只需搜索p1中第一个出现的s1,然后搜索s2中的第一个后续出现(从p1中的匹配末尾开始),依此类推。如果找到所有字符串,则模式匹配,否则它们不匹配