sequence_set.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:31k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: sequence_set.cpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 18:29:07  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.68
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: sequence_set.cpp,v 1000.4 2004/06/01 18:29:07 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Authors:  Paul Thiessen
  35. *
  36. * File Description:
  37. *      Classes to hold sets of sequences
  38. *
  39. * ===========================================================================
  40. */
  41. #ifdef _MSC_VER
  42. #pragma warning(disable:4018)   // disable signed/unsigned mismatch warning in MSVC
  43. #endif
  44. #include <ncbi_pch.hpp>
  45. #include <corelib/ncbistd.hpp>
  46. #include <corelib/ncbistre.hpp>
  47. #include <corelib/ncbistl.hpp>
  48. #include <objects/seqloc/Seq_id.hpp>
  49. #include <objects/seqloc/PDB_seq_id.hpp>
  50. #include <objects/seqloc/PDB_mol_id.hpp>
  51. #include <objects/general/Object_id.hpp>
  52. #include <objects/seqset/Bioseq_set.hpp>
  53. #include <objects/seq/Seq_inst.hpp>
  54. #include <objects/seq/Seq_data.hpp>
  55. #include <objects/seq/NCBIeaa.hpp>
  56. #include <objects/seq/IUPACaa.hpp>
  57. #include <objects/seq/NCBIstdaa.hpp>
  58. #include <objects/seq/NCBI4na.hpp>
  59. #include <objects/seq/NCBI8na.hpp>
  60. #include <objects/seq/NCBI2na.hpp>
  61. #include <objects/seq/IUPACna.hpp>
  62. #include <objects/seq/Seq_annot.hpp>
  63. #include <objects/general/Dbtag.hpp>
  64. #include <objects/seqloc/Textseq_id.hpp>
  65. #include <objects/seq/Seq_descr.hpp>
  66. #include <objects/seq/Seqdesc.hpp>
  67. #include <objects/seqblock/PDB_block.hpp>
  68. #include <objects/seqfeat/BioSource.hpp>
  69. #include <objects/seqfeat/Org_ref.hpp>
  70. #include <regex.h>  // regex from C-toolkit
  71. #include "sequence_set.hpp"
  72. #include "molecule.hpp"
  73. #include "structure_set.hpp"
  74. #include "cn3d_tools.hpp"
  75. #include "molecule_identifier.hpp"
  76. #include "messenger.hpp"
  77. USING_NCBI_SCOPE;
  78. USING_SCOPE(objects);
  79. BEGIN_SCOPE(Cn3D)
  80. static void UnpackSeqSet(CBioseq_set& bss, SequenceSet *parent, SequenceSet::SequenceList& seqlist)
  81. {
  82.     CBioseq_set::TSeq_set::iterator q, qe = bss.SetSeq_set().end();
  83.     for (q=bss.SetSeq_set().begin(); q!=qe; ++q) {
  84.         if (q->GetObject().IsSeq()) {
  85.             // only store amino acid or nucleotide sequences
  86.             if (q->GetObject().GetSeq().GetInst().GetMol() != CSeq_inst::eMol_aa &&
  87.                 q->GetObject().GetSeq().GetInst().GetMol() != CSeq_inst::eMol_dna &&
  88.                 q->GetObject().GetSeq().GetInst().GetMol() != CSeq_inst::eMol_rna &&
  89.                 q->GetObject().GetSeq().GetInst().GetMol() != CSeq_inst::eMol_na)
  90.                 continue;
  91.             const Sequence *sequence = new Sequence(parent, q->GetObject().SetSeq());
  92.             seqlist.push_back(sequence);
  93.         } else { // Bioseq-set
  94.             UnpackSeqSet(q->GetObject().SetSet(), parent, seqlist);
  95.         }
  96.     }
  97. }
  98. static void UnpackSeqEntry(CSeq_entry& seqEntry, SequenceSet *parent, SequenceSet::SequenceList& seqlist)
  99. {
  100.     if (seqEntry.IsSeq()) {
  101.         const Sequence *sequence = new Sequence(parent, seqEntry.SetSeq());
  102.         seqlist.push_back(sequence);
  103.     } else { // Bioseq-set
  104.         UnpackSeqSet(seqEntry.SetSet(), parent, seqlist);
  105.     }
  106. }
  107. SequenceSet::SequenceSet(StructureBase *parent, SeqEntryList& seqEntries) :
  108.     StructureBase(parent)
  109. {
  110.     SeqEntryList::iterator s, se = seqEntries.end();
  111.     for (s=seqEntries.begin(); s!=se; ++s)
  112.         UnpackSeqEntry(s->GetObject(), this, sequences);
  113.     TRACEMSG("number of sequences: " << sequences.size());
  114. }
  115. #define FIRSTOF2(byte) (((byte) & 0xF0) >> 4)
  116. #define SECONDOF2(byte) ((byte) & 0x0F)
  117. static void StringFrom4na(const vector< char >& vec, string *str, bool isDNA)
  118. {
  119.     if (SECONDOF2(vec.back()) > 0)
  120.         str->resize(vec.size() * 2);
  121.     else
  122.         str->resize(vec.size() * 2 - 1);
  123.     // first, extract 4-bit values
  124.     int i;
  125.     for (i=0; i<vec.size(); ++i) {
  126.         str->at(2*i) = FIRSTOF2(vec[i]);
  127.         if (SECONDOF2(vec[i]) > 0) str->at(2*i + 1) = SECONDOF2(vec[i]);
  128.     }
  129.     // then convert 4-bit values to ascii characters
  130.     for (i=0; i<str->size(); ++i) {
  131.         switch (str->at(i)) {
  132.             case 1: str->at(i) = 'A'; break;
  133.             case 2: str->at(i) = 'C'; break;
  134.             case 4: str->at(i) = 'G'; break;
  135.             case 8: isDNA ? str->at(i) = 'T' : str->at(i) = 'U'; break;
  136.             default:
  137.                 str->at(i) = 'X';
  138.         }
  139.     }
  140. }
  141. #define FIRSTOF4(byte) (((byte) & 0xC0) >> 6)
  142. #define SECONDOF4(byte) (((byte) & 0x30) >> 4)
  143. #define THIRDOF4(byte) (((byte) & 0x0C) >> 2)
  144. #define FOURTHOF4(byte) ((byte) & 0x03)
  145. static void StringFrom2na(const vector< char >& vec, string *str, bool isDNA)
  146. {
  147.     str->resize(vec.size() * 4);
  148.     // first, extract 4-bit values
  149.     int i;
  150.     for (i=0; i<vec.size(); ++i) {
  151.         str->at(4*i) = FIRSTOF4(vec[i]);
  152.         str->at(4*i + 1) = SECONDOF4(vec[i]);
  153.         str->at(4*i + 2) = THIRDOF4(vec[i]);
  154.         str->at(4*i + 3) = FOURTHOF4(vec[i]);
  155.     }
  156.     // then convert 4-bit values to ascii characters
  157.     for (i=0; i<str->size(); ++i) {
  158.         switch (str->at(i)) {
  159.             case 0: str->at(i) = 'A'; break;
  160.             case 1: str->at(i) = 'C'; break;
  161.             case 2: str->at(i) = 'G'; break;
  162.             case 3: isDNA ? str->at(i) = 'T' : str->at(i) = 'U'; break;
  163.         }
  164.     }
  165. }
  166. static void StringFromStdaa(const vector < char >& vec, string *str)
  167. {
  168.     static const char *stdaaMap = "-ABCDEFGHIKLMNPQRSTVWXYZU*";
  169.     str->resize(vec.size());
  170.     for (int i=0; i<vec.size(); ++i)
  171.         str->at(i) = stdaaMap[vec[i]];
  172. }
  173. Sequence::Sequence(SequenceSet *parent, ncbi::objects::CBioseq& bioseq) :
  174.     StructureBase(parent), bioseqASN(&bioseq), molecule(NULL), isProtein(false)
  175. {
  176.     int gi = MoleculeIdentifier::VALUE_NOT_SET, mmdbID = MoleculeIdentifier::VALUE_NOT_SET,
  177.         pdbChain = MoleculeIdentifier::VALUE_NOT_SET;
  178.     string pdbID, accession;
  179.     // get Seq-id info
  180.     CBioseq::TId::const_iterator s, se = bioseq.GetId().end();
  181.     for (s=bioseq.GetId().begin(); s!=se; ++s) {
  182.         if ((*s)->IsGi()) {
  183.             gi = (*s)->GetGi();
  184.         } else if ((*s)->IsPdb()) {
  185.             pdbID = (*s)->GetPdb().GetMol().Get();
  186.             if ((*s)->GetPdb().IsSetChain())
  187.                 pdbChain = (*s)->GetPdb().GetChain();
  188.             else
  189.                 pdbChain = ' ';
  190.         } else if ((*s)->IsLocal() && (*s)->GetLocal().IsStr()) {
  191.             accession = (*s)->GetLocal().GetStr();
  192.             // special case where local accession is actually a PDB chain + extra stuff
  193.             if (pdbID.size() == 0 && accession.size() >= 7 &&
  194.                     accession[4] == ' ' && accession[6] == ' ' && isalpha(accession[5])) {
  195.                 pdbID = accession.substr(0, 4);
  196.                 pdbChain = accession[5];
  197.                 accession.erase();
  198.             }
  199.         } else if ((*s)->IsGenbank() && (*s)->GetGenbank().IsSetAccession()) {
  200.             accession = (*s)->GetGenbank().GetAccession();
  201.         } else if ((*s)->IsSwissprot() && (*s)->GetSwissprot().IsSetAccession()) {
  202.             accession = (*s)->GetSwissprot().GetAccession();
  203.         } else if ((*s)->IsOther() && (*s)->GetOther().IsSetAccession()) {
  204.             accession = (*s)->GetOther().GetAccession();
  205.         } else if ((*s)->IsEmbl() && (*s)->GetEmbl().IsSetAccession()) {
  206.             accession = (*s)->GetEmbl().GetAccession();
  207.         } else if ((*s)->IsDdbj() && (*s)->GetDdbj().IsSetAccession()) {
  208.             accession = (*s)->GetDdbj().GetAccession();
  209.         }
  210.     }
  211.     if (gi == MoleculeIdentifier::VALUE_NOT_SET && pdbID.size() == 0 && accession.size() == 0) {
  212.         ERRORMSG("Sequence::Sequence() - can't parse SeqId");
  213.         return;
  214.     }
  215.     if (bioseq.IsSetDescr()) {
  216.         string defline, taxid;
  217.         CSeq_descr::Tdata::const_iterator d, de = bioseq.GetDescr().Get().end();
  218.         for (d=bioseq.GetDescr().Get().begin(); d!=de; ++d) {
  219.             // get "defline" from title or compound
  220.             if ((*d)->IsTitle()) {              // prefer title over compound
  221.                 defline = (*d)->GetTitle();
  222.             } else if (defline.size() == 0 && (*d)->IsPdb() && (*d)->GetPdb().GetCompound().size() > 0) {
  223.                 defline = (*d)->GetPdb().GetCompound().front();
  224.             }
  225.             // get taxonomy
  226.             if ((*d)->IsSource()) {
  227.                 if ((*d)->GetSource().GetOrg().IsSetTaxname())
  228.                     taxid = (*d)->GetSource().GetOrg().GetTaxname();
  229.                 else if ((*d)->GetSource().GetOrg().IsSetCommon())
  230.                     taxid = (*d)->GetSource().GetOrg().GetCommon();
  231.             }
  232.         }
  233.         if (taxid.size() > 0)
  234.             description = string("[") + taxid + ']';
  235.         if (defline.size() > 0) {
  236.             if (taxid.size() > 0) description += ' ';
  237.             description += defline;
  238.         }
  239.     }
  240.     // get link to MMDB id - mainly for CDD's where Biostrucs have to be loaded separately
  241.     if (bioseq.IsSetAnnot()) {
  242.         CBioseq::TAnnot::const_iterator a, ae = bioseq.GetAnnot().end();
  243.         for (a=bioseq.GetAnnot().begin(); a!=ae; ++a) {
  244.             if (a->GetObject().GetData().IsIds()) {
  245.                 CSeq_annot::C_Data::TIds::const_iterator i, ie = a->GetObject().GetData().GetIds().end();
  246.                 for (i=a->GetObject().GetData().GetIds().begin(); i!=ie; ++i) {
  247.                     if (i->GetObject().IsGeneral() &&
  248.                         i->GetObject().GetGeneral().GetDb() == "mmdb" &&
  249.                         i->GetObject().GetGeneral().GetTag().IsId()) {
  250.                         mmdbID = i->GetObject().GetGeneral().GetTag().GetId();
  251.                         break;
  252.                     }
  253.                 }
  254.                 if (i != ie) break;
  255.             }
  256.         }
  257.     }
  258.     if (mmdbID != MoleculeIdentifier::VALUE_NOT_SET)
  259.         TRACEMSG("sequence gi " << gi << ", PDB '" << pdbID << "' chain '" << (char) pdbChain <<
  260.             "', is from MMDB id " << mmdbID);
  261.     // get sequence string
  262.     if (bioseq.GetInst().GetRepr() == CSeq_inst::eRepr_raw && bioseq.GetInst().IsSetSeq_data()) {
  263.         // protein formats
  264.         if (bioseq.GetInst().GetSeq_data().IsNcbieaa()) {
  265.             sequenceString = bioseq.GetInst().GetSeq_data().GetNcbieaa().Get();
  266.             isProtein = true;
  267.         } else if (bioseq.GetInst().GetSeq_data().IsIupacaa()) {
  268.             sequenceString = bioseq.GetInst().GetSeq_data().GetIupacaa().Get();
  269.             isProtein = true;
  270.         } else if (bioseq.GetInst().GetSeq_data().IsNcbistdaa()) {
  271.             StringFromStdaa(bioseq.GetInst().GetSeq_data().GetNcbistdaa().Get(), &sequenceString);
  272.             isProtein = true;
  273.         }
  274.         // nucleotide formats
  275.         else if (bioseq.GetInst().GetSeq_data().IsIupacna()) {
  276.             sequenceString = bioseq.GetInst().GetSeq_data().GetIupacna().Get();
  277.             // convert 'T' to 'U' for RNA
  278.             if (bioseq.GetInst().GetMol() == CSeq_inst::eMol_rna) {
  279.                 for (int i=0; i<sequenceString.size(); ++i) {
  280.                     if (sequenceString[i] == 'T')
  281.                         sequenceString[i] = 'U';
  282.                 }
  283.             }
  284.         } else if (bioseq.GetInst().GetSeq_data().IsNcbi4na()) {
  285.             StringFrom4na(bioseq.GetInst().GetSeq_data().GetNcbi4na().Get(), &sequenceString,
  286.                 (bioseq.GetInst().GetMol() == CSeq_inst::eMol_dna));
  287.         } else if (bioseq.GetInst().GetSeq_data().IsNcbi8na()) {  // same repr. for non-X as 4na
  288.             StringFrom4na(bioseq.GetInst().GetSeq_data().GetNcbi8na().Get(), &sequenceString,
  289.                 (bioseq.GetInst().GetMol() == CSeq_inst::eMol_dna));
  290.         } else if (bioseq.GetInst().GetSeq_data().IsNcbi2na()) {
  291.             StringFrom2na(bioseq.GetInst().GetSeq_data().GetNcbi2na().Get(), &sequenceString,
  292.                 (bioseq.GetInst().GetMol() == CSeq_inst::eMol_dna));
  293.             if (bioseq.GetInst().IsSetLength() && bioseq.GetInst().GetLength() < sequenceString.length())
  294.                 sequenceString.resize(bioseq.GetInst().GetLength());
  295.         }
  296.         else {
  297.             ERRORMSG("Sequence::Sequence() - sequence " << gi
  298.                 << ": confused by sequence string format");
  299.             return;
  300.         }
  301.         // check length
  302.         if (bioseq.GetInst().IsSetLength() && bioseq.GetInst().GetLength() != sequenceString.length()) {
  303.             ERRORMSG("Sequence::Sequence() - sequence string length mismatch");
  304.             return;
  305.         }
  306.         // force uppercase
  307.         for (int i=0; i<sequenceString.length(); ++i)
  308.             sequenceString[i] = toupper(sequenceString[i]);
  309.     } else {
  310.         ERRORMSG("Sequence::Sequence() - sequence " << gi << ": confused by sequence representation");
  311.         return;
  312.     }
  313.     // get identifier (may be NULL if there's a problem!)
  314.     identifier = MoleculeIdentifier::GetIdentifier(this, pdbID, pdbChain, mmdbID, gi, accession);
  315. }
  316. void Sequence::AddMMDBAnnotTag(int mmdbID) const
  317. {
  318.     CBioseq::TAnnot::const_iterator a, ae = bioseqASN->GetAnnot().end();
  319.     CSeq_annot::C_Data::TIds::const_iterator i, ie;
  320.     bool found = false;
  321.     for (a=bioseqASN->GetAnnot().begin(); a!=ae; ++a) {
  322.         if ((*a)->GetData().IsIds()) {
  323.             for (i=(*a)->GetData().GetIds().begin(), ie=(*a)->GetData().GetIds().end(); i!=ie; ++i) {
  324.                 if ((*i)->IsGeneral() && (*i)->GetGeneral().GetDb() == "mmdb" &&
  325.                     (*i)->GetGeneral().GetTag().IsId())
  326.                 {
  327.                     found = true;
  328.                     TRACEMSG("mmdb link already present in sequence " << identifier->ToString());
  329.                     if ((*i)->GetGeneral().GetTag().GetId() != mmdbID ||
  330.                             (identifier->mmdbID != MoleculeIdentifier::VALUE_NOT_SET &&
  331.                                 identifier->mmdbID != mmdbID))
  332.                         ERRORMSG("Sequence::AddMMDBAnnotTag() - mmdbID mismatch");
  333.                     break;
  334.                 }
  335.             }
  336.         }
  337.         if (found) break;
  338.     }
  339.     if (!found) {
  340.         CRef < CSeq_id > seqid(new CSeq_id());
  341.         seqid->SetGeneral().SetDb("mmdb");
  342.         seqid->SetGeneral().SetTag().SetId(mmdbID);
  343.         CRef < CSeq_annot > annot(new CSeq_annot());
  344.         annot->SetData().SetIds().push_back(seqid);
  345.         (const_cast<Sequence*>(this))->bioseqASN->SetAnnot().push_back(annot);
  346.     }
  347. }
  348. CSeq_id * Sequence::CreateSeqId(void) const
  349. {
  350.     CSeq_id *sid = new CSeq_id();
  351.     FillOutSeqId(sid);
  352.     return sid;
  353. }
  354. void Sequence::FillOutSeqId(ncbi::objects::CSeq_id *sid) const
  355. {
  356.     sid->Reset();
  357.     CBioseq::TId::const_iterator i, ie = bioseqASN->GetId().end();
  358.     // use pdb id if present
  359.     for (i=bioseqASN->GetId().begin(); i!=ie; ++i) {
  360.         if ((*i)->IsPdb()) {
  361.             sid->Assign(**i);
  362.             return;
  363.         }
  364.     }
  365.     // use gi if present
  366.     for (i=bioseqASN->GetId().begin(); i!=ie; ++i) {
  367.         if ((*i)->IsGi()) {
  368.             sid->Assign(**i);
  369.             return;
  370.         }
  371.     }
  372.     // otherwise, just use the first one
  373.     if (bioseqASN->GetId().size() > 0)
  374.         sid->Assign(bioseqASN->GetId().front().GetObject());
  375.     else
  376.         ERRORMSG("Sequence::FillOutSeqId() - can't do Seq-id on sequence " << identifier->ToString());
  377.     // dangerous to create new Seq-id's...
  378. //    if (identifier->pdbID.size() > 0 && identifier->pdbChain != MoleculeIdentifier::VALUE_NOT_SET) {
  379. //        sid->SetPdb().SetMol().Set(identifier->pdbID);
  380. //        if (identifier->pdbChain != ' ') sid->SetPdb().SetChain(identifier->pdbChain);
  381. //    } else if (identifier->gi != MoleculeIdentifier::VALUE_NOT_SET) { // use gi
  382. //        sid->SetGi(identifier->gi);
  383. //    } else if (identifier->accession.size() > 0) {
  384. //        CObject_id *oid = new CObject_id();
  385. //        oid->SetStr(identifier->accession);
  386. //        sid->SetLocal(*oid);
  387. }
  388. void Sequence::AddCSeqId(SeqIdPtr *id, bool addAllTypes) const
  389. {
  390.     if (identifier->pdbID.size() > 0) {
  391.         PDBSeqIdPtr pdbid = PDBSeqIdNew();
  392.         pdbid->mol = StrSave(identifier->pdbID.c_str());
  393.         pdbid->chain = (Uint1) identifier->pdbChain;
  394.         ValNodeAddPointer(id, SEQID_PDB, pdbid);
  395.         if (!addAllTypes) return;
  396.     }
  397.     if (identifier->gi != MoleculeIdentifier::VALUE_NOT_SET) {
  398.         ValNodeAddInt(id, SEQID_GI, identifier->gi);
  399.         if (!addAllTypes) return;
  400.     }
  401.     if (identifier->accession.size() > 0) {
  402.         ObjectIdPtr local = ObjectIdNew();
  403.         local->str = StrSave(identifier->accession.c_str());
  404.         ValNodeAddPointer(id, SEQID_LOCAL, local);
  405.         if (!addAllTypes) return;
  406.     }
  407. }
  408. int Sequence::GetOrSetMMDBLink(void) const
  409. {
  410.     if (molecule) {
  411.         const StructureObject *object;
  412.         if (!molecule->GetParentOfType(&object)) return identifier->mmdbID;
  413.         if (identifier->mmdbID != MoleculeIdentifier::VALUE_NOT_SET &&
  414.             identifier->mmdbID != object->mmdbID)
  415.             ERRORMSG("Sequence::GetOrSetMMDBLink() - mismatched MMDB ID: identifier says "
  416.                 << identifier->mmdbID << ", StructureObject says " << object->mmdbID);
  417.         else
  418.             const_cast<MoleculeIdentifier*>(identifier)->mmdbID = object->mmdbID;
  419.     }
  420.     return identifier->mmdbID;
  421. }
  422. void Sequence::LaunchWebBrowserWithInfo(void) const
  423. {
  424.     string db = isProtein ? "Protein" : "Nucleotide";
  425.     string opt = isProtein ? "GenPept" : "GenBank";
  426.     CNcbiOstrstream oss;
  427.     oss << "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Search&doptcmdl=" << opt
  428.         << "&db=" << db << "&term=";
  429.     // prefer gi's, since accessions can be outdated
  430.     if (identifier->gi != MoleculeIdentifier::VALUE_NOT_SET) {
  431.         oss << identifier->gi;
  432.     } else if (identifier->pdbID.size() > 0) {
  433.         oss << identifier->pdbID.c_str();
  434.         if (identifier->pdbChain != ' ')
  435.             oss << (char) identifier->pdbChain;
  436.     } else if (identifier->accession.size() > 0) {
  437.         if (identifier->accession == "query" || identifier->accession == "consensus") return;
  438.         oss << identifier->accession.c_str();
  439.     }
  440.     oss << '';
  441.     LaunchWebPage(oss.str());
  442.     delete oss.str();
  443. }
  444. static bool Prosite2Regex(const string& prosite, string *regex, int *nGroups)
  445. {
  446.     try {
  447.         // check allowed characters
  448.         static const string allowed = "-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[],(){}<>.";
  449.         int i;
  450.         for (i=0; i<prosite.size(); ++i)
  451.             if (allowed.find(toupper(prosite[i])) == string::npos) break;
  452.         if (i != prosite.size()) throw "invalid ProSite character";
  453.         if (prosite[prosite.size() - 1] != '.') throw "ProSite pattern must end with '.'";
  454.         // translate into real regex syntax;
  455.         regex->erase();
  456.         *nGroups = 0;
  457.         bool inGroup = false;
  458.         for (int i=0; i<prosite.size(); ++i) {
  459.             // handle grouping and termini
  460.             bool characterHandled = true;
  461.             switch (prosite[i]) {
  462.                 case '-': case '.': case '>':
  463.                     if (inGroup) {
  464.                         *regex += ')';
  465.                         inGroup = false;
  466.                     }
  467.                     if (prosite[i] == '>') *regex += '$';
  468.                     break;
  469.                 case '<':
  470.                     *regex += '^';
  471.                     break;
  472.                 default:
  473.                     characterHandled = false;
  474.                     break;
  475.             }
  476.             if (characterHandled) continue;
  477.             if (!inGroup && (
  478.                     (isalpha(prosite[i]) && toupper(prosite[i]) != 'X') ||
  479.                     prosite[i] == '[' || prosite[i] == '{')) {
  480.                 *regex += '(';
  481.                 (*nGroups)++;
  482.                 inGroup = true;
  483.             }
  484.             // translate syntax
  485.             switch (prosite[i]) {
  486.                 case '(':
  487.                     *regex += '{';
  488.                     break;
  489.                 case ')':
  490.                     *regex += '}';
  491.                     break;
  492.                 case '{':
  493.                     *regex += "[^";
  494.                     break;
  495.                 case '}':
  496.                     *regex += ']';
  497.                     break;
  498.                 case 'X': case 'x':
  499.                     *regex += '.';
  500.                     break;
  501.                 default:
  502.                     *regex += toupper(prosite[i]);
  503.                     break;
  504.             }
  505.         }
  506.     }
  507.     catch (const char *err) {
  508.         ERRORMSG("Prosite2Regex() - " << err);
  509.         return false;
  510.     }
  511.     return true;
  512. }
  513. bool Sequence::HighlightPattern(const string& prositePattern) const
  514. {
  515.     // setup regex syntax
  516.     reg_syntax_t newSyntax = RE_CONTEXT_INDEP_ANCHORS | RE_CONTEXT_INVALID_OPS | RE_INTERVALS |
  517.         RE_LIMITED_OPS | RE_NO_BK_BRACES | RE_NO_BK_PARENS | RE_NO_EMPTY_RANGES;
  518.     reg_syntax_t oldSyntax = re_set_syntax(newSyntax);
  519.     bool retval = true;
  520.     try {
  521.         // allocate structures
  522.         static re_pattern_buffer *patternBuffer = NULL;
  523.         static re_registers *registers = NULL;
  524.         if (!patternBuffer) {
  525.             // new pattern initialized to zero
  526.             patternBuffer = (re_pattern_buffer *) calloc(1, sizeof(re_pattern_buffer));
  527.             if (!patternBuffer) throw "can't allocate pattern buffer";
  528.             patternBuffer->fastmap = (char *) calloc(256, sizeof(char));
  529.             if (!patternBuffer->fastmap) throw "can't allocate fastmap";
  530.             registers = (re_registers *) calloc(1, sizeof(re_registers));
  531.             if (!registers) throw "can't allocate registers";
  532.             patternBuffer->regs_allocated = REGS_UNALLOCATED;
  533.         }
  534.         // update pattern buffer if not the same pattern as before
  535.         static string previousPrositePattern;
  536.         static int nGroups;
  537.         int i;
  538.         if (prositePattern != previousPrositePattern) {
  539.             // convert from ProSite syntax
  540.             string regexPattern;
  541.             if (!Prosite2Regex(prositePattern, &regexPattern, &nGroups))
  542.                 throw "error converting ProSite to regex syntax";
  543.             // create pattern buffer
  544.             TRACEMSG("compiling pattern '" << regexPattern << "'");
  545.             const char *error = re_compile_pattern(regexPattern.c_str(), regexPattern.size(), patternBuffer);
  546.             if (error) throw error;
  547.             // optimize pattern buffer
  548.             int err = re_compile_fastmap(patternBuffer);
  549.             if (err) throw "re_compile_fastmap internal error";
  550.             previousPrositePattern = prositePattern;
  551.         }
  552.         // do the search, finding all non-overlapping matches
  553.         int start = 0;
  554.         while (start < Length()) {
  555.             int result = re_search(patternBuffer, sequenceString.c_str(),
  556.                 Length(), start, Length(), registers);
  557.             if (result == -1)
  558.                 break;
  559.             else if (result == -2)
  560.                 throw "re_search internal error";
  561.             // re_search gives the longest hit, but we want the shortest; so try to find the
  562.             // shortest hit within the hit already found by limiting the length of the string
  563.             // allowed to be included in the search. (This isn't very efficient! but
  564.             // the regex API doesn't have an option for finding the shortest hit...)
  565.             int stringSize = start + 1;
  566.             while (stringSize <= Length()) {
  567.                 result = re_search(patternBuffer, sequenceString.c_str(),
  568.                     stringSize, start, stringSize, registers);
  569.                 if (result >= 0) break;
  570.                 ++stringSize;
  571.             }
  572.             // parse the match registers, highlight ranges
  573. //            TESTMSG("found match starting at " << identifier->ToString() << " loc " << result+1);
  574.             int lastMatched = result;
  575.             for (i=1; i<registers->num_regs; ++i) {
  576.                 int from = registers->start[i], to = registers->end[i] - 1;
  577.                 if (from >= 0 && to >= 0) {
  578.                     if (to > lastMatched) lastMatched = to;
  579.                     // highlight this ranage
  580. //                    TESTMSG("register " << i << ": from " << from+1 << " to " << to+1);
  581.                     GlobalMessenger()->AddHighlights(this, from, to);
  582.                 }
  583.             }
  584.             start = lastMatched + 1;
  585.         }
  586.     } catch (const char *err) {
  587.         ERRORMSG("Sequence::HighlightPattern() - " << err);
  588.         retval = false;
  589.     }
  590.     // cleanup
  591.     re_set_syntax(oldSyntax);
  592.     return retval;
  593. }
  594. END_SCOPE(Cn3D)
  595. /*
  596. * ---------------------------------------------------------------------------
  597. * $Log: sequence_set.cpp,v $
  598. * Revision 1000.4  2004/06/01 18:29:07  gouriano
  599. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.68
  600. *
  601. * Revision 1.68  2004/05/21 21:41:39  gorelenk
  602. * Added PCH ncbi_pch.hpp
  603. *
  604. * Revision 1.67  2004/05/21 17:29:51  thiessen
  605. * allow conversion of mime to cdd data
  606. *
  607. * Revision 1.66  2004/03/15 18:27:12  thiessen
  608. * prefer prefix vs. postfix ++/-- operators
  609. *
  610. * Revision 1.65  2004/03/01 22:56:09  thiessen
  611. * convert 'T' to 'U' for RNA with IUPACna
  612. *
  613. * Revision 1.64  2004/02/19 17:05:06  thiessen
  614. * remove cn3d/ from include paths; add pragma to disable annoying msvc warning
  615. *
  616. * Revision 1.63  2004/01/05 17:09:16  thiessen
  617. * abort import and warn if same accession different gi
  618. *
  619. * Revision 1.62  2003/11/26 20:37:54  thiessen
  620. * prefer gi for URLs
  621. *
  622. * Revision 1.61  2003/11/20 22:08:49  thiessen
  623. * update Entrez url
  624. *
  625. * Revision 1.60  2003/09/03 18:14:01  thiessen
  626. * hopefully fix Seq-id issues
  627. *
  628. * Revision 1.59  2003/08/30 14:01:15  thiessen
  629. * use existing CSeq_id instead of creating new one
  630. *
  631. * Revision 1.58  2003/07/14 18:37:08  thiessen
  632. * change GetUngappedAlignedBlocks() param types; other syntax changes
  633. *
  634. * Revision 1.57  2003/03/13 14:26:18  thiessen
  635. * add file_messaging module; split cn3d_main_wxwin into cn3d_app, cn3d_glcanvas, structure_window, cn3d_tools
  636. *
  637. * Revision 1.56  2003/02/03 19:20:05  thiessen
  638. * format changes: move CVS Log to bottom of file, remove std:: from .cpp files, and use new diagnostic macros
  639. *
  640. * Revision 1.55  2002/12/12 15:04:11  thiessen
  641. * fix for report launch on nucleotides
  642. *
  643. * Revision 1.54  2002/12/09 16:25:04  thiessen
  644. * allow negative score threshholds
  645. *
  646. * Revision 1.53  2002/11/22 19:54:29  thiessen
  647. * fixes for wxMac/OSX
  648. *
  649. * Revision 1.52  2002/11/19 21:19:44  thiessen
  650. * more const changes for objects; fix user vs default style bug
  651. *
  652. * Revision 1.51  2002/11/06 00:18:10  thiessen
  653. * fixes for new CRef/const rules in objects
  654. *
  655. * Revision 1.50  2002/10/11 17:21:39  thiessen
  656. * initial Mac OSX build
  657. *
  658. * Revision 1.49  2002/09/13 14:21:45  thiessen
  659. * finish hooking up browser launch on unix
  660. *
  661. * Revision 1.48  2002/09/06 18:56:48  thiessen
  662. * add taxonomy to description
  663. *
  664. * Revision 1.47  2002/09/05 17:14:14  thiessen
  665. * create new netscape window on unix
  666. *
  667. * Revision 1.46  2002/07/12 13:24:10  thiessen
  668. * fixes for PSSM creation to agree with cddumper/RPSBLAST
  669. *
  670. * Revision 1.45  2002/01/24 20:08:17  thiessen
  671. * fix local id problem
  672. *
  673. * Revision 1.44  2002/01/19 02:34:46  thiessen
  674. * fixes for changes in asn serialization API
  675. *
  676. * Revision 1.43  2002/01/11 15:49:01  thiessen
  677. * update for Mac CW7
  678. *
  679. * Revision 1.42  2001/11/30 14:59:55  thiessen
  680. * add netscape launch for Mac
  681. *
  682. * Revision 1.41  2001/11/30 14:02:05  thiessen
  683. * progress on sequence imports to single structures
  684. *
  685. * Revision 1.40  2001/11/27 16:26:09  thiessen
  686. * major update to data management system
  687. *
  688. * Revision 1.39  2001/09/27 15:37:59  thiessen
  689. * decouple sequence import and BLAST
  690. *
  691. * Revision 1.38  2001/08/21 01:10:31  thiessen
  692. * fix lit. launch for nucleotides
  693. *
  694. * Revision 1.37  2001/08/09 19:07:13  thiessen
  695. * add temperature and hydrophobicity coloring
  696. *
  697. * Revision 1.36  2001/07/24 15:02:59  thiessen
  698. * use ProSite syntax for pattern searches
  699. *
  700. * Revision 1.35  2001/07/23 20:09:23  thiessen
  701. * add regex pattern search
  702. *
  703. * Revision 1.34  2001/07/19 19:14:38  thiessen
  704. * working CDD alignment annotator ; misc tweaks
  705. *
  706. * Revision 1.33  2001/07/10 16:39:55  thiessen
  707. * change selection control keys; add CDD name/notes dialogs
  708. *
  709. * Revision 1.32  2001/06/21 02:02:34  thiessen
  710. * major update to molecule identification and highlighting ; add toggle highlight (via alt)
  711. *
  712. * Revision 1.31  2001/06/18 21:48:27  thiessen
  713. * add [PACC] to Entrez query for PDB id's
  714. *
  715. * Revision 1.30  2001/06/02 17:22:46  thiessen
  716. * fixes for GCC
  717. *
  718. * Revision 1.29  2001/05/31 18:47:09  thiessen
  719. * add preliminary style dialog; remove LIST_TYPE; add thread single and delete all; misc tweaks
  720. *
  721. * Revision 1.28  2001/05/31 14:32:03  thiessen
  722. * better netscape launch for unix
  723. *
  724. * Revision 1.27  2001/05/25 01:38:16  thiessen
  725. * minor fixes for compiling on SGI
  726. *
  727. * Revision 1.26  2001/05/24 13:32:32  thiessen
  728. * further tweaks for GTK
  729. *
  730. * Revision 1.25  2001/05/15 23:48:37  thiessen
  731. * minor adjustments to compile under Solaris/wxGTK
  732. *
  733. * Revision 1.24  2001/05/02 16:35:15  thiessen
  734. * launch entrez web page on sequence identifier
  735. *
  736. * Revision 1.23  2001/04/20 18:03:22  thiessen
  737. * add ncbistdaa parsing
  738. *
  739. * Revision 1.22  2001/04/18 15:46:53  thiessen
  740. * show description, length, and PDB numbering in status line
  741. *
  742. * Revision 1.21  2001/03/28 23:02:17  thiessen
  743. * first working full threading
  744. *
  745. * Revision 1.20  2001/02/16 00:40:01  thiessen
  746. * remove unused sequences from asn data
  747. *
  748. * Revision 1.19  2001/02/13 01:03:57  thiessen
  749. * backward-compatible domain ID's in output; add ability to delete rows
  750. *
  751. * Revision 1.18  2001/02/08 23:01:50  thiessen
  752. * hook up C-toolkit stuff for threading; working PSSM calculation
  753. *
  754. * Revision 1.17  2001/01/25 20:21:18  thiessen
  755. * fix ostrstream memory leaks
  756. *
  757. * Revision 1.16  2001/01/09 21:45:00  thiessen
  758. * always use pdbID as title if known
  759. *
  760. * Revision 1.15  2001/01/04 18:20:52  thiessen
  761. * deal with accession seq-id
  762. *
  763. * Revision 1.14  2000/12/29 19:23:39  thiessen
  764. * save row order
  765. *
  766. * Revision 1.13  2000/12/28 20:43:09  vakatov
  767. * Do not use "set" as identifier.
  768. * Do not include <strstream>. Use "CNcbiOstrstream" instead of "ostrstream".
  769. *
  770. * Revision 1.12  2000/12/21 23:42:15  thiessen
  771. * load structures from cdd's
  772. *
  773. * Revision 1.11  2000/12/20 23:47:48  thiessen
  774. * load CDD's
  775. *
  776. * Revision 1.10  2000/12/15 15:51:47  thiessen
  777. * show/hide system installed
  778. *
  779. * Revision 1.9  2000/11/17 19:48:13  thiessen
  780. * working show/hide alignment row
  781. *
  782. * Revision 1.8  2000/11/11 21:15:54  thiessen
  783. * create Seq-annot from BlockMultipleAlignment
  784. *
  785. * Revision 1.7  2000/09/15 19:24:22  thiessen
  786. * allow repeated structures w/o different local id
  787. *
  788. * Revision 1.6  2000/09/03 18:46:49  thiessen
  789. * working generalized sequence viewer
  790. *
  791. * Revision 1.5  2000/08/30 23:46:27  thiessen
  792. * working alignment display
  793. *
  794. * Revision 1.4  2000/08/30 19:48:41  thiessen
  795. * working sequence window
  796. *
  797. * Revision 1.3  2000/08/28 23:47:19  thiessen
  798. * functional denseg and dendiag alignment parsing
  799. *
  800. * Revision 1.2  2000/08/28 18:52:42  thiessen
  801. * start unpacking alignments
  802. *
  803. * Revision 1.1  2000/08/27 18:52:22  thiessen
  804. * extract sequence information
  805. *
  806. */