【问题标题】:RegEx on a string for a match AND a match REGARDLESS of order匹配字符串的正则表达式和匹配,无论顺序如何
【发布时间】:2014-11-03 02:36:57
【问题描述】:

我正在编写一个 Java 程序,一次搜索 15 个字符的 DNA 序列,找到 C 和 G 出现次数最多的部分。我认为检查整个 DNA 序列中子字符串的任何区域是最快的of 15 完全由 C 和 G 组成,如果不存在,则查找具有 14 个 C 和 G 以及 1 个 A 或 T 的子字符串。然后如果没有出现,则 13 个 CG 和 2 个 AT 等...

尝试为此找到一个正则表达式解决方案对我来说很困难。我想出了一个使用此代码的测试用例,但我无法让 RegEx 工作。我认为语法可能是错误的,我从未在 Java 中使用过 RegExes。抱歉,我大概能弄清楚语法,我只需要帮助正则表达式本身匹配正确的东西。

public class DNAChecker{

     public static void main(String []args){
        String checkThis= "ggccggccaggccgg";

        if (checkThis.matches( “(?=.*[CcGg]{14})(?=.*[AaTt]{1})” ) ) {
            System.out.println("This program works.");
        } else {
            System.out.println("This program doesn't work.");
        }
     }
}

我理解它的方式以及我在相关线程中看到的内容,如果这可以通过正则表达式完成,我至少可以接近这一点。现在我正在考虑它,我认为这不能确保总匹配长度为 15 个字符......即如果 checkThis 长度超过 15 个字符并且总共有 14 个 CG 和 1 个 AT,而不是连续地,这仍然是正确的。所以 xxxxggccggxxccaggccggxxxxxx 是真的。使用 .contains 而不是 .matches 会确保长度限制吗?

无论如何,像这样的单行 RegEx 会比计算每个子字符串的 C 和 G 更快吗?我还没有上过算法课。

请记住,这个程序的最终形式将接受一个可变长度的字符串,并搜索长度为 n 的子字符串,而不是每次都搜索 15 个。(我知道如何处理这些要求,所以无需告诉我有关 Scanner 或参数如何工作的信息!)我只是一个尝试使用绝地级 RegEx 东西的 RegEx 菜鸟......如果你也可以推荐一本书让我成为 RegExes 的向导,那将是激进的。 非常感谢您的回复!

【问题讨论】:

  • 恐怕正则表达式对于这个问题可能不会对你太有用。我建议只计算字符串中 cs 和 gs 的数量
  • 关于正则表达式的信息/教程,试试这个网站:regular-expressions.info
  • 您能否提供一些输入字符串的示例以及您想要输出的内容?如果我理解正确,您有一个相当大的输入字符串,并查找最多 15 个字符的序列,其中仅包含 cg,最后带有 at。对吗?
  • 要记住的一点是String.matches(regex)Pattern.compile(regex).matcher(String).find() 之间的区别。前者寻找一个 exact 匹配,而后者只是寻找正则表达式作为原始输入的子字符串。因此,在您的情况下,您可能希望使用 Pattern.compile(regex).matcher(String).find() 来确定正则表达式是否与输入的任何子字符串匹配。

标签: java regex string search


【解决方案1】:

正则表达式是任何语言中最诱人的特征之一。然而,仅仅因为它们很酷、很性感并且看起来很强大并不意味着它们是正确的工具。对于这样的事情,一个简单的状态机就足够了,而且可能会快得多。下面的代码查找仅包含cg 的最长子字符串,并且可以通过将多个子字符串添加到集合中轻松地进行调整以保留多个子字符串。

    String data = "acgtcgcgagagagggggcccataatggg";
    int    longestPos = 0;
    int    longestLen = 0;
    int p=-1;
    for (int i=0; i<data.length(); i++)
    {
        char c = data.charAt(i);
        if (c == 'c' || c == 'g')  // Is this the droid you're looking for?
        {
            if (p==-1)  // Are we not yet in an interesting string?
                p = i;  // If so, save the position of this start of substring.
        }
        else  // Not a c or g
        {
            if (p != -1 && i-p > longestLen)  // Are we in an interesting string longer than the previous longest?
            {
                longestPos = p;     // Save the starting position
                longestLen = i-p;   // Save the length
            }
            p = -1;   // We're no longer inside an interesting string
        }
    }

    // Handle the case where the last substring was 'interesting'
    if (p != -1 && i-p > longestLen)
    {
        longestPos = p;     // Save the starting position
        longestLen = i-p;   // Save the length
    }

    System.out.printf("Longest string is at position %d for length %d", longestPos, longestLen);

对于“让我们在不适用的地方使用正则表达式”的规范响应,请参阅this post

【讨论】:

    【解决方案2】:

    我不完全确定我是否正确理解了您的问题,所以我假设您要查找由cs 和gs 后跟a 或@987654324 组成的最长字符序列@。

    我进一步假设您的输入字符串仅包含这些字符。

    因此,您可以尝试使用Pattern.compile(regex).matcher(input).find() 来获取所有匹配的组。然后按长度排序,得到最长的序列。

    为此,您可以使用以下正则表达式:(?i)([cg]+[at])(i?) 使表达式不区分大小写)。

    例子:

    String input = "ccgccgCggatccgCATccggcccgggggtatt";
    
    List<String> sequences = new ArrayList<>();
    
    //find the sequences
    Matcher m = Pattern.compile("(?i)([cg]+[at])").matcher( input );
    while( m.find() ) {
      sequences.add( m.group().toLowerCase() );
    }
    
    //sort by descending length
    Collections.sort( sequences, new Comparator<String>() {
      public int compare( String lhs, String rhs ) {
        //switch arguments for descending sort
        return Integer.compare( rhs.length(), lhs.length());
      }
    });
    
    System.out.println( sequences );
    

    输出为:[ccggcccgggggt, ccgccgcgga, ccgca]

    如果您只想允许这些序列的特定长度,则需要更改正则表达式:
    (?i)(?&lt;=^|[^cg])([cg]{10,15}[at])

    变化:

    (?&lt;=^|[^cg]) 表示序列必须位于输入的开头或除cg 之外的任何内容之前。要匹配较长序列的部分,即 gcga 超出 cccgcga,您只需将其从正则表达式中删除即可。

    [cg]{10,15} 表示 cs 和 gs 的序列长度必须在 10 到 15 个字符之间,即不匹配较短的序列,而如果不使用 (?&lt;=^|[^cg]),则可能匹配较长的序列。使用精确的长度,例如15个字符,使用上面的条件,把这个条件改成[cg]{15}

    【讨论】:

      猜你喜欢
      • 2019-08-25
      • 1970-01-01
      • 2023-03-13
      • 2011-11-08
      • 2023-03-18
      • 2012-06-05
      • 2013-12-25
      相关资源
      最近更新 更多