OpenMS
Loading...
Searching...
No Matches
IonNaming.h
Go to the documentation of this file.
1// Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin
2// SPDX-License-Identifier: BSD-3-Clause
3//
4// --------------------------------------------------------------------------
5// $Maintainer: Timo Sachsenberg $
6// $Authors: Timo Sachsenberg $
7// --------------------------------------------------------------------------
8
9#pragma once
10
12#include <OpenMS/OpenMSConfig.h>
13
14#include <cctype>
15#include <climits>
16#include <string>
17
18namespace OpenMS
19{
31 namespace IonNaming
32 {
39 constexpr int MAX_REPEATED_SIGNS = 8;
40
54 inline std::string chargeSuffix(int charge)
55 {
56 if (charge == 0) { return std::string(); }
57 const char sign = (charge < 0) ? '-' : '+';
58 // negate in a wider type: std::abs(INT_MIN) is undefined behaviour
59 const long long magnitude = (charge < 0) ? -static_cast<long long>(charge) : static_cast<long long>(charge);
60 if (magnitude <= MAX_REPEATED_SIGNS) { return std::string((Size)magnitude, sign); }
61 return sign + std::to_string(magnitude);
62 }
63
78 inline int chargeFromName(const std::string& ion_name)
79 {
80 const std::string name = ion_name.substr(0, ion_name.find_first_of("\r\n"));
81 if (name.empty()) { return 0; }
82
83 // parse name[begin, end) as a charge magnitude; false if it is not one that fits in an int
84 auto toCharge = [&name](std::string::size_type begin, std::string::size_type end, bool negative, int& out) {
85 if (end <= begin || (end - begin) > 10) { return false; }
86 long long value = 0;
87 for (std::string::size_type i = begin; i < end; ++i) { value = value * 10 + (name[i] - '0'); }
88 if (negative) { value = -value; }
89 if (value < (long long)INT_MIN || value > (long long)INT_MAX) { return false; }
90 out = (int)value;
91 return true;
92 };
93
94 // mzPAF: '^' followed by an optionally signed number, then either the end of the name or one of
95 // mzPAF's following fields ('/' mass delta, '*' confidence). Checked before the trailing-number
96 // form below, because mzPAF's mass delta is itself a signed number at the end of the name
97 // ("y4-H2O1^2/-1") and would otherwise be read as the charge.
98 const std::string::size_type caret = name.rfind('^');
99 if (caret != std::string::npos)
100 {
101 std::string::size_type c = caret + 1;
102 const bool negative = (c < name.size() && name[c] == '-');
103 if (c < name.size() && (name[c] == '+' || name[c] == '-')) { ++c; }
104 std::string::size_type end = c;
105 while (end < name.size() && std::isdigit((unsigned char)name[end])) { ++end; }
106 // anything other than a field delimiter after the digits means this is not a charge token
107 const bool token_ends = (end == name.size() || name[end] == '/' || name[end] == '*');
108 int value = 0;
109 if (token_ends && toCharge(c, end, negative, value)) { return value; }
110 }
111
112 const char last = name.back();
113
114 // trailing run of signs, e.g. "y3+", "b2++", "c1-", "a3-B-"
115 if (last == '+' || last == '-')
116 {
117 std::string::size_type run = name.size();
118 while (run > 0 && name[run - 1] == last) { --run; }
119 const int count = (int)(name.size() - run);
120 return (last == '-') ? -count : count;
121 }
122
123 // trailing sign plus number, e.g. "y3+3" (note "y1-H2O1" must NOT match: 'O' is not a sign).
124 // Not when the name carries an mzPAF field: mzPAF spells the charge with the caret handled above,
125 // so a trailing signed number after '/' or '*' is its mass delta or confidence, not a charge --
126 // "y3/1.2e-05" would otherwise read as charge -5.
127 if (std::isdigit((unsigned char)last) && name.find_first_of("/*") == std::string::npos)
128 {
129 std::string::size_type d = name.size();
130 while (d > 0 && std::isdigit((unsigned char)name[d - 1])) { --d; }
131 int value = 0;
132 if (d > 0 && (name[d - 1] == '+' || name[d - 1] == '-') && toCharge(d, name.size(), name[d - 1] == '-', value))
133 {
134 return value;
135 }
136 }
137 return 0;
138 }
139
155 inline std::string withCharge(const std::string& ion_name, int charge)
156 {
157 if (charge == 0 || chargeFromName(ion_name) != 0) { return ion_name; }
158 std::string named = ion_name;
159 const std::string::size_type eol = named.find_first_of("\r\n");
160 named.insert((eol == std::string::npos) ? named.size() : eol, chargeSuffix(charge));
161 return named;
162 }
163
178 inline UInt ordinalFromName(const std::string& ion_name)
179 {
180 // the ordinal follows an ion letter, so anything else in front of the digits is not one:
181 // "+3" is a charge and "12" is not an ion name at all
182 if (ion_name.empty() || std::isalpha((unsigned char)ion_name[0]) == 0) { return 0; }
183 std::string::size_type end = 1;
184 while (end < ion_name.size() && std::isdigit((unsigned char)ion_name[end])) { ++end; }
185 if (end == 1) { return 0; }
186 // bounded: an ordinal is at most a peptide length, anything longer is not one
187 if (end - 1 > 9) { return 0; }
188 UInt value = 0;
189 for (std::string::size_type i = 1; i < end; ++i) { value = value * 10 + (UInt)(ion_name[i] - '0'); }
190 return value;
191 }
192 } // namespace IonNaming
193} // namespace OpenMS
unsigned int UInt
Unsigned integer type.
Definition Types.h:64
size_t Size
Size type e.g. used as variable which can hold result of size()
Definition Types.h:97
int chargeFromName(const std::string &ion_name)
The charge an ion name spells out, or 0 if it does not spell one.
Definition IonNaming.h:78
std::string withCharge(const std::string &ion_name, int charge)
The ion name to display for a peak annotated with ion_name and charge.
Definition IonNaming.h:155
UInt ordinalFromName(const std::string &ion_name)
The fragment ordinal an ion name spells out ("y12++" -> 12), or 0 if it does not spell one.
Definition IonNaming.h:178
constexpr int MAX_REPEATED_SIGNS
Largest charge magnitude still written as a run of signs.
Definition IonNaming.h:39
std::string chargeSuffix(int charge)
The charge notation to append to an ion name, e.g. "+" for 1, "--" for -2.
Definition IonNaming.h:54
Main OpenMS namespace.
Definition openswathalgo/include/OpenMS/OPENSWATHALGO/DATAACCESS/ISpectrumAccess.h:19