source: tags/arb_5.0/GENOM_IMPORT/Feature.cxx

Last change on this file was 5806, checked in by westram, 15 years ago
  • Feature::addQualifiedEntry throws error, if value is "\"" (should no longer occur, but just in case)
  • quoted multiline qualifier entries are now detected even if first line only contains the opening quotes
  • type: expection → exception
File size: 4.7 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : Feature.cxx                                        //
4//   Purpose   :                                                    //
5//                                                                  //
6//   Coded by Ralf Westram (coder@reallysoft.de) in November 2006   //
7//   Institute of Microbiology (Technical University Munich)        //
8//   http://www.arb-home.de/                                        //
9//                                                                  //
10// ================================================================ //
11#include "Feature.h"
12#include <cctype>
13
14
15using namespace std;
16
17
18Feature::Feature(const string& Type, const string& locationString)
19    : type(Type)
20    , location(parseLocation(locationString)) 
21{
22}
23
24inline void setOrAppendQualifiedEntry(stringMap& qualifiers, const string& qualifier, const string& value) {
25    stringMapIter existing = qualifiers.find(qualifier);
26    if (existing != qualifiers.end()) { // existing qualifier
27        existing->second.append(1, '\n'); // append separated by LF
28        existing->second.append(value);
29    }
30    else {
31        qualifiers[qualifier] = value;
32    }
33}
34
35void Feature::addQualifiedEntry(const string& qualifier, const string& value) {
36    // search for quotes
37    size_t vlen = value.length();
38
39    gi_assert(vlen>0);
40
41    stringCIter start = value.begin();
42    stringCIter end   = start+vlen-1;
43
44    if (*start == '"') {
45        if (vlen == 1 || *end != '"') {
46            throw GBS_global_string("Unclosed quotes at qualifier '%s'", qualifier.c_str());
47        }
48        // skip quotes :
49        ++start;
50        // end points to '"'
51    }
52    else {
53        ++end; // point behind last character
54    }
55
56    setOrAppendQualifiedEntry(qualifiers, qualifier, string(start, end));
57}
58
59static void appendData(string& id, const string& data, int maxAppend) {
60    // extract alphanumeric text portion from start of 'data'
61    // until some other character is found
62
63    if (maxAppend >= 2) {
64        size_t old_id_len = id.length();
65
66        id.append(1, '_');
67        maxAppend--;
68
69        stringCIter end          = data.end();
70        bool        insideWord   = false;
71        bool        seenNonDigit = false;
72
73        for (stringCIter i = data.begin(); maxAppend>0 && i != end; ++i) {
74            char c = *i;
75            if (isalnum(c)) {
76                if (!insideWord) c = toupper(c);
77                id.append(1, c);
78                maxAppend--;
79                insideWord         = true;
80                if (!seenNonDigit && isalpha(c)) { seenNonDigit = true; }
81            }
82            else if (isspace(c) || c == '-') { // ignore space and '-'
83                insideWord = false;
84            }
85            else {
86                break; // anything else -> abort
87            }
88        }
89
90        if (!seenNonDigit) { // data only contained digits (as far as data has been scanned)
91            id.resize(old_id_len); // undo changes
92        }
93    }
94}
95
96string Feature::createGeneName() const
97{
98    stringMapCIter not_found = qualifiers.end();
99    stringMapCIter product   = qualifiers.find("product");
100    stringMapCIter gene      = qualifiers.find("gene");
101
102    const size_t maxidlen = 30; // just an approx. limit
103    string       id       = type; // use gene type
104
105    id.reserve(maxidlen+10);
106    if (gene != not_found) { // append gene name
107        appendData(id, gene->second, maxidlen-id.length());
108    }
109
110    if (product != not_found) {
111        appendData(id, product->second, maxidlen-id.length());
112    }
113
114    // now ensure that id doesn't end with digit
115    // (if it would, creating unique gene names gets too complicated)
116    if (isdigit(id[id.length()-1])) {
117        if (id.length() == maxidlen) id.resize(maxidlen-1);
118        id.append(1, 'X');
119    }
120
121    return id;
122}
123
124void Feature::expectLocationInSequence(long seqLength) const
125{
126    // test whether feature location is inside sequence
127    // throw error otherwise
128
129    if (!location->isInRange(1, seqLength)) {
130        throw GBS_global_string("Illegal feature location (outside sequence 1..%li)", seqLength);
131    }
132}
133
134void Feature::fixEmptyQualifiers() {
135    // some qualifiers in feature table may be empty
136
137    stringMapIter e = qualifiers.end();
138    for (stringMapIter i = qualifiers.begin(); i != e; ++i) {
139        if (i->second.empty()) { // with all qualifiers, that have no content, do..
140            if (i->first == "replace") {
141                // ARB cannot store empty strings!
142                // Since '/replace=""' means 'delete location', we need to store this
143                // this information differently.
144                i->second = "<empty>"; //
145            }
146        }
147    }
148}
Note: See TracBrowser for help on using the repository browser.