我正在编写一个Java程序,一次搜索15个字符的DNA序列,找到C和G出现次数最多的部分。我认为检查整个DNA序列的任何区域都是最快的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和G更快?我还没上过算法课。
请记住,最终形式的这个程序将接受一串可变长度,并且每次搜索长度为n的子串,而不是15。(我知道如何处理这些要求,所以不需要告诉我关于Scanner或者参数是如何工作的!)我只是一个RegEx noob尝试使用Jedi级RegEx的东西......如果你能推荐一本书让我成为RegExes的向导这也是激进的。 非常感谢您的回复!
答案 0 :(得分:3)
正则表达式是任何语言最诱人的功能之一。然而,仅仅因为它们酷而性感且看起来非常强大并不意味着它们是正确的工具。对于这样的事情,一个简单的状态机就足够了,并且可能会更快。下面的代码找到了仅包含c
和g
的最长子字符串,并且可以通过将它们添加到集合中来轻松调整以保留多个子字符串。
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
答案 1 :(得分:0)
我不完全确定我是否正确理解了您的问题,因此我假设您希望找到由c
和g
组成的最长字符序列,然后是{{ 1}}或a
。
我进一步假设你的输入字符串只包含那些字符。
因此,您可以尝试使用t
来获取所有匹配的组。然后按长度排序,得到最长的序列。
要实现这一点,您可以使用以下正则表达式: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)(?<=^|[^cg])([cg]{10,15}[at])
表示序列必须在输入的开头或除(?<=^|[^cg])
或c
之外的任何内容之前。要匹配较长序列的部分内容,即g
中的gcga
,请将其从正则表达式中删除。
cccgcga
表示cs和gs的序列长度必须介于10到15个字符之间,即如果不使用[cg]{10,15}
,则较短的序列将不匹配,而较长的序列可能会匹配。要使用精确的长度,例如15个字符,使用上述条件并将此条件更改为(?<=^|[^cg])
。