C# 正则表达式查找';足够好了';序列

C# 正则表达式查找';足够好了';序列,c#,regex,C#,Regex,我希望实现一些算法来帮助我匹配不完美的序列 假设我有一个存储的abbabba序列,我想在大量字符流中找到“看起来像”的东西 如果我允许我的算法有两个通配符(差异),我如何使用Regex匹配这样的内容:where(and)标记差异: A(A)BABAB(A)A or (B)BBA(A)ABBA int differences = 0; // Count of discrepancies you've detected int tolerance = 7; // Limit of

我希望实现一些算法来帮助我匹配不完美的序列

假设我有一个存储的abbabba序列,我想在大量字符流中找到“看起来像”的东西

如果我允许我的算法有两个通配符(差异),我如何使用Regex匹配这样的内容:where(and)标记差异:

A(A)BABAB(A)A 
or 
(B)BBA(A)ABBA
int differences = 0;    // Count of discrepancies you've detected
int tolerance = 7;    // Limit of discrepancies you'll allow

CheckStrings(int differences, int tolerance) {
    for (i = 0; i < StringA.Length; i++)
    {
        if (StringA[i] != StringB[i]) {
            differences++;
            if (differences > tolerance) {
                return false;
            }
        }
    }
    return true;
}
我的困境是,我希望在一大串字符中找到这些潜在的目标匹配(有缺陷)。 因此,在以下情况下:

ABBDBABDBCBDBABDB(A(A)BABAB(A)A)DBDBABDBCBDBAB
ADBDBABDBDBDBCBDBABCBDBABCBDBABCBDBABABBBDBABABBCD
DBABCBDABDBABCBCBDBABABDABDBABCBDBABABDDABCBDBABAB
我必须能够搜索这些“足够接近”的匹配
其中括号表示:(足够好的匹配(差异))

编辑:为了在本例中更加正式,如果N-2个字符与原始字符相同(2个差异),则可以接受长度为N的匹配

我以前使用过正则表达式,但只是为了找到完美的序列——而不是“看起来”像的序列

希望这足够清楚,可以得到一些建议。
谢谢你的阅读和帮助

任何
A
B
的组合都有效吗

bool isMatch = Regex.IsMatch(inputString, "^[AB()]+$")

我不认为这可以通过正则表达式来实现(如果可以,我不熟悉语法)。但是,您可以使用动态规划算法来实现


编辑:如果您不需要处理已切换位置的字母,一种更简单的方法是只比较两个字符串中的每对字符,然后计算差异的数量。

我不知道如何使用正则表达式,但它应该非常简单


我可能只是将字符串拆分,然后逐个字符进行比较。如果你得到一个不同的计数,并移动到下一个字符。如果超过2个差异,则转到下一个完整字符串。

我认为没有好的正则表达式来处理这种情况。(或者至少,没有一个不占用三行文字并导致多个子弹射入你的脚)然而,这并不意味着你不能解决这个问题

根据字符串的大小(我假设每个字符串不会有数百万个字符),我看不到任何东西阻止您使用单个循环按顺序比较单个字符,同时记录差异:

A(A)BABAB(A)A 
or 
(B)BBA(A)ABBA
int differences = 0;    // Count of discrepancies you've detected
int tolerance = 7;    // Limit of discrepancies you'll allow

CheckStrings(int differences, int tolerance) {
    for (i = 0; i < StringA.Length; i++)
    {
        if (StringA[i] != StringB[i]) {
            differences++;
            if (differences > tolerance) {
                return false;
            }
        }
    }
    return true;
}
int差异=0;//您检测到的差异计数
整数公差=7;//你们允许的差异限度
检查字符串(整数差异、整数公差){
对于(i=0;i公差){
返回false;
}
}
}
返回true;
}

大多数时候,不要担心字符串太长而无法放入循环。在幕后,任何评估字符串中每个字符的代码都将以某种形式循环。除非你真的有数百万个字符要处理,否则循环应该可以很好地完成任务。

我将跳过“regex”部分,重点关注:

有没有比对每个位置进行嵌套循环通配符更好的方法

听起来好像有一种编程方式可以帮助你。关于迭代两个IEnumerable。通过同时迭代两个字符串,您可以在O(n)时间内完成任务。更好的是,如果你知道你的容忍度(最多2个错误),你有时可以比O(n)更快地完成

这是我写的一个简单的例子。它可能需要根据您自己的情况进行调整,但这可能是一个很好的起点

static void imperfectMatch(String original, String testCase, int tolerance)
{
    int mistakes = 0;

    if (original.Length == testCase.Length)
    {
        using (CharEnumerator enumerator1 = original.GetEnumerator())
        using (CharEnumerator enumerator2 = testCase.GetEnumerator())
        {
            while (enumerator1.MoveNext() && enumerator2.MoveNext())
            {
                if (mistakes >= tolerance)
                    break;
                if (enumerator1.Current != enumerator2.Current)
                    mistakes++;
            }
        }
    }
    else
        mistakes = -1;

    Console.WriteLine(String.Format("Original String: {0}", original));
    Console.WriteLine(String.Format("Test Case String: {0}", testCase));
    Console.WriteLine(String.Format("Number of errors: {0}", mistakes));
    Console.WriteLine();
}

对于足够小的模式(ABCD),您可以生成一个regexp:

..CD|.B.D|.BC.|A..D|A.C.|AB..

您还可以编写一个自定义比较循环

您可以使用LINQ来表现友好和富有表现力

要使用此选项,请确保代码顶部有一个
using System.Linq

假设

  • source
    是存储的目标模式
  • test
    是要测试的字符串
那你就可以了

public static bool IsValid(string source, string test) 
{
  return test != null  
         && source != null 
         && test.Length == source.Length 
         && test.Where((x,i) => source[i] != x).Count() <=2
}
根据评论中的要求,对其工作原理进行一点解释

在C#中,字符串可以被视为字符数组,这意味着可以对其使用Linq方法

test.Where((x,i) => source[i] != x)
这使用重载,其中对于测试中的每个字符,
x
被分配给字符,
i
被分配给索引。如果源中位置i处的条件字符不等于x,则输出到结果中

Skip(2)
这跳过了前两个结果

Any()
如果还剩下任何结果,则返回true,否则返回false。因为linq在该值为false时延迟执行,所以函数退出,而不是计算字符串的其余部分

public static bool IsValid(string source, string test) 
{
   return test != null  
          && source != null 
          && test.Length == source.Length 
          && !test.Where((x,i) => source[i] != x).Skip(2).Any();
}
然后,在整个测试前加上一个“!”来否定它表示我们想知道哪里没有更多的结果

现在,为了匹配子字符串,您需要的行为类似于正则表达式回溯

public static IEnumerable<int> GetMatches(string source, string test)
{
   return from i in Enumerable.Range(0,test.Length - source.Length)
      where IsValid(source, !test.Skip(i).Take(source.Length))
          select i;
}

public static bool IsValid(string source, IEnumerable<char> test) 
{
   return test.Where((x,i) => source[i] != x).Skip(2).Any();
}

我认为要问的第一个问题是“什么是匹配的条件?”它必须是特定长度、包含特定字符、在@Doc中包含特定序列吗?在本例中,在获取这些匹配的情况下,匹配与原始匹配非常相似,但允许有2个不正确的字符(通配符).你能不能更正式、更准确一点?更正式定义的一个例子是:如果至少有N-2个字符匹配,则大小为N的目标序列匹配。另一个正式的定义是:大小从N-2到N+2的目标序列匹配,前提是可以通过不超过2次的编辑操作(添加/删除/替换)将其缩减为模式序列。@Doc这只是一个非常简单的示例,实际上我使用了4个唯一的字符,因此(ABCD)。我现在记录了一个签名,ABCDBD。然后,我搜索字符样本,它看起来可能是(与津贴(通配符)为不同的