查找字符串中的所有子字符串并存储结果?

时间:2015-05-10 14:53:07

标签: c++ string

class ORF_Finder {
public:
    void findORFs(string & strand, int sizeOfStrand); 
    vector<string> orf1Strands; 
    vector<string> orf2Strands;
    vector<string> orf3Strands; 
private:
    string newStrand;
    string newSub;
};    


void ORF_Finder::findORFs(string & strand, int sizeOfStrand) {

        int pos, pos1, index = 0;

for (int i = 0; i < strand.size(); i++) {
        pos = strand.find("ATG"); 
        pos1 = strand.find("TAA"); 
        newSub = strand.substr(pos, pos1);
        newStrand.insert(index, newSub);
        strand.erase(pos, pos1);
        index = index + 3; 

        if ((pos1 % 3 == 0) && (pos1 >= pos + 21)) {
            orf1Strands.push_back(newStrand); 
        }

        else if ((pos1 % 3 == 1) && (pos1 >= pos + 21)) { 
            orf2Strands.push_back(newStrand);
        }

        else if ((pos1 % 3 == 2) && (pos1 >= pos + 21)) {
            orf3Strands.push_back(newStrand); 
        }
   }
}
假设所有字符串都已声明,我正在“使用命名空间std”。

我的目标是向用户询问输入的DNA链(例如:“TCAATGCGCGCTACCATGCGGAGCTCTGGGCCCAAATTTCATCCATAACTGGGGCCCTTTTAAGGGCCCGGGAAATTT”)并查找子串以“ATG”开头并以“TAA”,“TAG”或“TGA”结尾的所有实例(为简单起见,我省略了“TAG”和“TGA”。

子串将如此:“ATG ...... ...... ...... TAA”然后它将被存储到一个矢量中以便以后使用。但是,我想找到每个阅读框的多个实例(ORF1应该从进口链的“T”开始,ORF2应该从进口链的“C”开始,ORF3应该从“A”开始。导入的链)并且应该在三元组中工作,因此在if语句中包含mod 3。 “pos1&gt; = pos + 21”的目的是使每个子串长至少七个密码子。

上面的代码是我迄今为止所做的,但显然,这是不正确的。我试图告诉pos找到“ATG”和pos1找到“TAA”。 newSub是将从“ATG”生成到“TAA”的子字符串,并且将生成newStrand以包含子字符串。然后我会删除链的一部分(以避免重复)和增加索引。

对于长篇描述感到抱歉,但我一直在强调这一点,我已经尽力解决这个问题。

3 个答案:

答案 0 :(得分:1)

Knutt-Morris Pratt是最快的解决方案。 Aho-corasick算法是一种来自kmp算法的广义版本。基本上它是一个带有从广度优先搜索计算的失败链接的特里。您可以尝试我的PHP实现phpahocorasick @ codeplex.com。然后,您需要添加通配符以查找所有子字符串。

答案 1 :(得分:0)

简单:

  1. 扫描整个字符串以查找开始或结束序列的出现次数。
  2. 如果找到结束序列,请从上一个启动序列中提取部件。
  3. 您将拥有一些角落,例如:处理可以不同配对的多个信号序列,但这些只是正常的编程。

    您的方法存在的问题是您不是从头到尾扫描字符串,而是从头开始重复搜索开头和结尾。你需要在最后一个位置后继续。查看string类的各种{{1}}函数,了解如何执行此操作。

答案 2 :(得分:0)

这是一种可能的实施方式。

特点:

  • 可以处理大字符串,因为它只保留一个初始字符串的副本
  • 接受一个任意的初始序列(此处为“ATG”)
  • 接受许多结束序列(此处为“TAA”,“TAG”或“TGA”)
  • 仅接受至少7个密码子的子串
  • 子字符串仅由初始字符串和长度中的索引(以节省内存)
  • 描述
  • 根据您的要求,根据其索引的模3将结果保存在3个不同的向量中

代码:

#include <iostream>
#include <string>
#include <stdexcept>
#include <vector>

class Strand {
    const std::string* data;
    size_t begin;
    size_t len;

public:
    Strand(const std::string& data, size_t begin, size_t end): begin(begin),
        len(end - begin), data(&data) {
            if (end <= begin) {
                throw std::invalid_argument("end < begin");
            }
    }
    std::string getString() const {
        const char *beg = data->c_str();
        beg += begin;
        return std::string(beg, len);
    }
};

class Parser {
    const std::string& data;
    const std::string& first;
    const std::vector<std::string>& end;
    size_t dataLen;
    std::vector<Strand> orf1Strands;
    std::vector<Strand> orf2Strands;
    std::vector<Strand> orf3Strands;

public:
    enum TypStrand {
        one = 0, two, three
    };
    Parser(const std::string& data, const std::string& first,
        const std::vector<std::string>& end): data(data),
        first(first), end(end) {
            dataLen = data.length();
    }

    void parse();
    const std::vector<Strand>& getVector(int typ) const {
        switch(typ) {
            case 0 : return orf1Strands;
            case 1 : return orf2Strands;
            default : return orf3Strands;
        }
    }
    const std::vector<Strand>& getVector(TypStrand typ) const {
        return getVector((int) typ);
    }

};

void Parser::parse() {
    size_t pos=0;
    size_t endSize = end.size();
    std::string firstChars = "";
    for(size_t i=0; i<endSize; i++) {
        firstChars += end[i].at(0);
    }

    for(;;) {
        pos = data.find(first, pos);
        if (pos == std::string::npos) break;
        size_t strandEnd = pos + 18;
        for(;;) {
            if (strandEnd + 3 >= dataLen) break;
            strandEnd = data.find_first_of(firstChars, strandEnd);
            if ((strandEnd - pos) % 3 != 0) {
                strandEnd += 1;
                continue;
            }
            if (strandEnd + 3 >= dataLen) break;
            for (size_t i=0; i<endSize; i++) {
                if (data.compare(strandEnd, end[i].length(), end[i]) == 0) {
                    std::cout << "Found sequence ended with " << end[i] << std::endl;
                    switch(pos %3) {
                        case 0 :
                            orf1Strands.push_back(Strand(data, pos,
                                strandEnd + 3));
                            break;
                        case 1 :
                            orf2Strands.push_back(Strand(data, pos,
                                strandEnd + 3));
                            break;
                        case 2 :
                            orf3Strands.push_back(Strand(data, pos,
                                strandEnd + 3));
                            break;
                    }
                    pos = strandEnd + end[i].length() - 1;
                    break;
                }
            }
            if (pos > strandEnd) break;
            strandEnd += 3;
        }
        if (strandEnd + 3 >= dataLen) break;
        pos = pos + 1;
    }
}

using namespace std;

int main() {
    std::string first = "ATG";
    vector<string> end;
    std::string ends[] = { "TAA", "TAG", "TGA"};
    for (int i=0; i< sizeof(ends)/sizeof(std::string); i++) {
        end.push_back(ends[i]);
    }

    string data = "TCAATGCGCGCTACCATGCGGAGCTCTGGGCCCAAATTTC"
        "ATCCATAACTGGGGCCCTTTTAAGGGCCCGGGAAATTT";

    Parser parser(data, first, end);
    parser.parse();

    for (int i=0; i<3; i++) {
        int typ = i;
        const vector<Strand>& vect = parser.getVector(typ);
        cout << "Order " << i << " : " << vect.size() << endl;
        if (vect.size() > 0) {
            for(size_t j=0; j<vect.size(); j++) {
                cout << vect[i].getString() << endl;
            }
        }
    }
    return 0;
}

Todo:

  • 添加评论
  • 修复enum TypStrand的管理:一旦编写了程序,我认为最好有三个向量的数组,而不是三个不同的向量。
  • 最少数量的密码子应该是可配置的
  • 对角落案件进行更密集的测试
  • 3是一个神奇的数字,实际上应该表示为常数