TkN 2.7
Toolkit for Nuclei
Loading...
Searching...
No Matches
tkstring.cpp
1/********************************************************************************
2 * Copyright (c) : Université de Lyon 1, CNRS/IN2P3, UMR5822, *
3 * IP2I, F-69622 Villeurbanne Cedex, France *
4 * Normandie Université, ENSICAEN, UNICAEN, CNRS/IN2P3, *
5 * LPC Caen, F-14000 Caen, France *
6 * Contibutor(s) : *
7 * Jérémie Dudouet jeremie.dudouet@cnrs.fr [2020] *
8 * Diego Gruyer diego.gruyer@cnrs.fr [2020] *
9 * *
10 * Licensed under the MIT License <http://opensource.org/licenses/MIT>. *
11 * SPDX-License-Identifier: MIT *
12 ********************************************************************************/
13#include "tkstring.h"
14
15#include <array>
16#include <cctype>
17#include <cstdarg>
18#include <cstdio>
19#include <cstdlib>
20#include <cmath>
21#include <algorithm>
22#include <string>
23#include <string_view>
24
25namespace tkn {
35}
36
37using namespace tkn;
38
39namespace {
40
41std::string format_string(const char *_format, va_list _arguments)
42{
43 if (!_format) return {};
44
45 va_list arguments_copy;
46 va_copy(arguments_copy, _arguments);
47 const int required_size = std::vsnprintf(nullptr, 0, _format, arguments_copy);
48 va_end(arguments_copy);
49 if (required_size < 0) return {};
50
51 std::string result(static_cast<std::size_t>(required_size) + 1, '\0');
52 std::vsnprintf(result.data(), result.size(), _format, _arguments);
53 result.resize(static_cast<std::size_t>(required_size));
54 return result;
55}
56
57unsigned char unsigned_character(char _character)
58{
59 return static_cast<unsigned char>(_character);
60}
61
62tkstring normalized_number(const tkstring &_input, bool _replace_comma)
63{
64 tkstring normalized;
65 normalized.reserve(_input.size());
66 for (const char character : _input) {
67 if (character == ' ') continue;
68 normalized += (_replace_comma && character == ',') ? '.' : character;
69 }
70 return normalized;
71}
72
73}
74
75std::string tkn::wrap_text(const tkstring &_text, size_t _first_content_col, size_t _continuation_col, size_t _max_line_width)
76{
77 const size_t min_content_width = 20;
78 const size_t first_avail = _first_content_col < _max_line_width ? _max_line_width - _first_content_col : min_content_width;
79 const size_t continuation_avail = _continuation_col < _max_line_width ? _max_line_width - _continuation_col : min_content_width;
80 const std::string continuation_indent(_continuation_col, ' ');
81
82 auto wrap_paragraph = [&](const std::string &_paragraph, size_t _first_avail) {
83 std::string result;
84 size_t pos = 0;
85 bool first_chunk = true;
86 while (pos < _paragraph.size()) {
87 if (!first_chunk) result += "\n" + continuation_indent;
88 const size_t content_avail = first_chunk ? _first_avail : continuation_avail;
89 if (_paragraph.size() - pos <= content_avail) {
90 result += _paragraph.substr(pos);
91 break;
92 }
93 size_t wrap_at = _paragraph.rfind(' ', pos + content_avail);
94 if (wrap_at == std::string::npos || wrap_at <= pos) {
95 result += _paragraph.substr(pos, content_avail);
96 pos += content_avail;
97 } else {
98 result += _paragraph.substr(pos, wrap_at - pos);
99 pos = wrap_at + 1;
100 while (pos < _paragraph.size() && _paragraph[pos] == ' ') pos++;
101 }
102 first_chunk = false;
103 }
104 return result;
105 };
106
107 auto paragraphs = _text.tokenize_from_string("\n");
108 std::string wrapped;
109 bool first_para = true;
110 for (auto &para : paragraphs) {
111 if (!first_para) wrapped += "\n" + continuation_indent;
112 wrapped += wrap_paragraph(para, first_para ? first_avail : continuation_avail);
113 first_para = false;
114 }
115 return wrapped;
116}
117
119{
120 std::transform(begin(), end(), begin(),[](unsigned char _c){ return std::tolower(_c); });
121 return *this;
122}
123
125{
126 std::transform(begin(), end(), begin(),[](unsigned char _c){ return std::toupper(_c); });
127 return *this;
128}
129
139
141{
142 bool has_digit = false;
143 if (empty()) return false;
144 for (const char character : *this) {
145 if (character == ' ') continue;
146 if (!std::isdigit(unsigned_character(character))) return false;
147 has_digit = true;
148 }
149 return has_digit;
150}
151
166
168{
169 const tkstring normalized = normalized_number(*this, true);
170 if (normalized.empty()) return false;
171 char *end = nullptr;
172 const double value = std::strtod(normalized.c_str(), &end);
173 return end != normalized.c_str() && *end == '\0' && std::isfinite(value);
174}
175
176//tkstring tkstring::energy_to_string(double _val, int _precision)
177//{
178// int exp_value = (_val == 0) ? 0 : 1 + (int)std::floor(std::log10(std::fabs(_val) ) );
179// int exp_error = (_precision == 0) ? 0 : 1 + (int)std::floor(std::log10(std::fabs(_precision) ) );
180
181// std::ostringstream os;
182
183// if(_precision<0) os.precision(exp_value+exp_error);
184// else os.precision(exp_value);
185// os << _val;
186
187// tkstring result = os.str();
188// return result;
189//}
190
191//tkstring tkstring::energy_error_to_string(double _val, int _precision)
192//{
193// int exp_error = (_precision == 0) ? 0 : 1 + (int)std::floor(std::log10(std::fabs(_precision) ) );
194// if(_precision>0) exp_error = 1 + (int)std::floor(std::log10(std::fabs(_val) ) );
195// std::ostringstream os;
196
197// os.precision(exp_error);
198// os << _val;
199
200// tkstring result = os.str();
201// return result;
202//}
203
204
209
210int tkstring::atoi() const
211{
212 if (find(' ') == npos) return std::atoi(data());
213 return std::atoi(normalized_number(*this, false).data());
214}
215
216int64_t tkstring::atoll() const
217{
218 if (find(' ') == npos) return std::atoll(data());
219 return std::atoll(normalized_number(*this, false).data());
220}
221
226double tkstring::atof() const
227{
228 if (find(',') == npos && find(' ') == npos) return std::atof(data());
229 return std::atof(normalized_number(*this, true).data());
230}
231
237size_t tkstring::index(const char *_s, size_t _pos, ECaseCompare _cmp) const
238{
239 if (!_s || _pos > size()) return npos;
240 if(_cmp == ECaseCompare::kExact) return find(_s,_pos);
241
242 const std::string_view pattern(_s);
243 if (pattern.empty()) return _pos;
244 const auto match_position = std::search(
245 begin() + static_cast<std::ptrdiff_t>(_pos), end(),
246 pattern.begin(), pattern.end(),
247 [](char left, char right) {
248 return std::tolower(unsigned_character(left)) ==
249 std::tolower(unsigned_character(right));
250 });
251 return match_position == end() ? npos : static_cast<size_t>(match_position - begin());
252}
253
258
259bool tkstring::equal_to(const char *_s, ECaseCompare _cmp) const
260{
261 if (!_s) return false;
262 if (_cmp == kExact) return compare(_s) == 0;
263 const std::string_view other(_s);
264 return size() == other.size() && std::equal(
265 begin(), end(), other.begin(),
266 [](char left, char right) {
267 return std::tolower(unsigned_character(left)) ==
268 std::tolower(unsigned_character(right));
269 });
270}
271
272bool tkstring::ends_with(const char *_s, ECaseCompare _cmp) const
273{
274 if (!_s) return false;
275
276#if defined(__cpp_lib_starts_ends_with) && __cpp_lib_starts_ends_with >= 201711L
277 if (_cmp == kExact) return std::string::ends_with(_s);
278#endif
279
280 size_t l = strlen(_s);
281 if (l > length()) return false;
282 const auto offset = length() - l;
283 if (_cmp == kExact) return compare(offset, l, _s) == 0;
284 return std::equal(
285 begin() + static_cast<std::ptrdiff_t>(offset), end(), _s,
286 [](char left, char right) {
287 return std::tolower(unsigned_character(left)) ==
288 std::tolower(unsigned_character(right));
289 });
290}
291
292std::vector<tkstring> tkstring::tokenize(const tkstring &_delim) const
293{
294 std::vector<tkstring> tokens;
295 if (empty()) return tokens;
296 if (_delim.empty()) {
297 tokens.push_back(*this);
298 return tokens;
299 }
300
301 size_t start = find_first_not_of(_delim);
302 while (start != npos) {
303 const size_t stop = find_first_of(_delim, start);
304 tokens.emplace_back(std::string::substr(start, stop - start));
305 if (stop == npos) break;
306 start = find_first_not_of(_delim, stop);
307 }
308
309 return tokens;
310}
311
312std::vector<tkstring> tkstring::tokenize_from_string(const tkstring &_delim) const {
313 std::vector<tkstring> tokens;
314 if (empty()) return tokens;
315 if (_delim.empty()) {
316 tokens.push_back(*this);
317 return tokens;
318 }
319 size_t start = 0, pos = 0;
320
321 // Boucle tant qu'on trouve le délimiteur complet
322 while ((pos = find(_delim, start)) != npos) {
323 tkstring token = substr(start, pos - start);
324 if (token.length()) {
325 tokens.push_back(token);
326 }
327 // On avance de la longueur du délimiteur
328 start = pos + _delim.length();
329 }
330
331 // Ajoute le dernier segment (après le dernier délimiteur)
332 tkstring token = substr(start);
333 if (token.length()) {
334 tokens.push_back(token);
335 }
336
337 return tokens;
338}
339
340tkstring& tkstring::replace_all(const char *_s1, size_t _ls1, const char *_s2, size_t _ls2)
341{
342 if (_s1 && _ls1 > 0) {
343 size_t pos = 0;
344 while ((pos = find(_s1,pos,_ls1)) != npos) {
345 replace(pos, _ls1, _s2, _ls2);
346 pos += _ls2;
347 }
348 }
349 return *this;
350}
351
353{
354 std::size_t found = find_last_of(_s1);
355 tkstring name = substr(found+1);
356
357 return name;
358}
359
361{
362 std::size_t found = find_last_of(_s1);
363 tkstring name = substr(0,found);
364
365 return name;
366}
367
368tkstring tkstring::Form(const char * _format, ...)
369{
370 va_list argptr;
371 va_start(argptr, _format);
372 tkstring result(format_string(_format, argptr));
373 va_end(argptr);
374 return result;
375}
376
378{
379 tkstring temp(*this);
380 return temp;
381}
382
384{
385 for(size_t i=0 ; i<length() ; i++) {
386 if ((*this)[i] >= 'a' && (*this)[i] <= 'z') {
387 (*this)[i] -= ('a' - 'A');
388 return *this;
389 }
390 }
391 return *this;
392}
393
395{
396 tkstring result{};
397
398 const char *cp = data();
399 size_t len = length();
400
401 for (size_t i = 0; i < len; ++i)
402 if (std::isalpha(unsigned_character(cp[i])))
403 result += cp[i];
404 return result;
405}
406
407
409{
410 tkstring result{};
411
412 const char *cp = data();
413 size_t len = length();
414
415 for (size_t i = 0; i < len; ++i)
416 if (!std::isalpha(unsigned_character(cp[i])))
417 result += cp[i];
418 return result;
419}
420
426
428{
429 const char *cp = data();
430 size_t len = length();
431 if (len == 0) return false;
432 for (size_t i = 0; i < len; ++i)
433 if (!std::isalpha(unsigned_character(cp[i])))
434 return false;
435 return true;
436}
437
438const char* tkstring::form(const char * _format, ...)
439{
440 // A small per-thread ring preserves several results used in the same
441 // expression while retaining the historical const char* API.
442 thread_local std::array<std::string, 8> buffers;
443 thread_local std::size_t next_buffer = 0;
444 std::string &result = buffers[next_buffer++ % buffers.size()];
445
446 va_list argptr;
447 va_start(argptr, _format);
448 result = format_string(_format, argptr);
449 va_end(argptr);
450 return result.c_str();
451}
452
453tkstring::tkstring(double _value, double _error): std::string("")
454{
455 double y = _value;
456 double ey = _error;
457
458 tkstring sy = Form("%1.2e", y);
459 tkstring sey = Form("%1.1e", ey);
460
461 tkstring sy_dec, sy_exp, sey_dec, sey_exp;
462 double y_dec, ey_dec;
463 int y_exp, ey_exp;
464
465 //Recup de la valeur y
466 std::vector<tkstring> loa_y = sy.tokenize("e");
467 sy_dec = loa_y.front();
468 sy_exp = loa_y.back();
469
470 y_dec = sy_dec.atof();
471 y_exp = sy_exp.atoi();
472
473 //Recup de la valeur ey
474 std::vector<tkstring> loa_ey = sey.tokenize("e");
475
476 sey_dec = loa_ey.front();
477 sey_exp = loa_ey.back();
478
479 ey_dec = sey_dec.atof();
480 ey_exp = sey_exp.atoi();
481
482 double err = ey_dec * pow(10., ey_exp - y_exp);
483 tkstring s;
484
485 if (!Form("%1.2g", y_dec).contains(".") && err >= 1) {
486
487 if (!Form("%1.2g", err).contains(".")) {
488 if (y_exp == ey_exp) s = Form("%1.2g.0(%g.0).10$^{%d}$", y_dec, ey_dec, y_exp);
489 else s = Form("%1.3g.0(%g.0).10$^{%d}$", y_dec, err, y_exp);
490 } else if (Form("%1.2g", err) == Form("%1.1g", err) && Form("%1.2g", err).contains(".")) {
491 if (y_exp == ey_exp) s = Form("%1.2g.0(%g0).10$^{%d}$", y_dec, ey_dec, y_exp);
492 else s = Form("%1.3g.0(%g0).10$^{%d}$", y_dec, err, y_exp);
493 } else {
494 if (y_exp == ey_exp) s = Form("%1.2g.0(%g).10$^{%d}$", y_dec, ey_dec, y_exp);
495 else s = Form("%1.3g.0(%g).10$^{%d}$", y_dec, err, y_exp);
496 }
497 } else if (Form("%1.3g", y_dec) == Form("%1.2g", y_dec) && Form("%1.2g", y_dec).contains(".") && err < 1) {
498 if (!Form("%1.2g", err).contains(".")) {
499 if (y_exp == ey_exp) s = Form("%1.2g0(%g.0).10$^{%d}$", y_dec, ey_dec, y_exp);
500 else s = Form("%1.3g0(%g.0).10$^{%d}$", y_dec, err, y_exp);
501 } else if (Form("%1.2g", err) == Form("%1.1g", err) && Form("%1.2g", err).contains(".")) {
502 if (y_exp == ey_exp) s = Form("%1.2g0(%g0).10$^{%d}$", y_dec, ey_dec, y_exp);
503 else s = Form("%1.3g0(%g0).10$^{%d}$", y_dec, err, y_exp);
504 } else {
505 if (y_exp == ey_exp) s = Form("%1.2g0(%g).10$^{%d}$", y_dec, ey_dec, y_exp);
506 else s = Form("%1.3g0(%g).10$^{%d}$", y_dec, err, y_exp);
507 }
508 } else if (!Form("%1.2g", err).contains(".")) {
509 if (y_exp == ey_exp) s = Form("%1.2g(%g.0).10$^{%d}$", y_dec, ey_dec, y_exp);
510 else s = Form("%1.3g(%g.0).10$^{%d}$", y_dec, err, y_exp);
511 } else if (Form("%1.2g", err) == Form("%1.1g", err) && Form("%1.2g", err).contains(".")) {
512 if (y_exp == ey_exp) s = Form("%1.2g(%g0).10$^{%d}$", y_dec, ey_dec, y_exp);
513 else s = Form("%1.3g(%g0).10$^{%d}$", y_dec, err, y_exp);
514 } else {
515 if (y_exp == ey_exp) s = Form("%1.2g(%g).10$^{%d}$", y_dec, ey_dec, y_exp);
516 else s = Form("%1.3g(%g).10$^{%d}$", y_dec, err, y_exp);;
517 }
518
519 s.replace_all(".10$^{0}$", "");
520 s.replace_all("0)", ")");
521
522 *this = s;
523}
524
526{
527 // Remove any superfluous whitespace (or tabs or newlines) from string (modify string)
528 // i.e. transform " Mary Had\tA Little \n Laaaaaaaaaaaaaaaaaamb"
529 // into "Mary Had A Little Lamb"
530
532
533 return *this;
534}
535
536int tkstring::count_string(const tkstring &_st) const
537{
538 if (_st.empty()) return 0;
539 int count = 0;
540 size_t pos=0;
541
542 while ((pos = find(_st,pos)) != npos) {
543 pos += _st.length();
544 count++;
545 }
546
547 return count;
548}
549
551{
552 // Remove any superfluous whitespace (or tabs or newlines) from string (does not modify string)
553 // i.e. transform " Mary Had\tA Little \n Laaaaaaaaaaaaaaaaaamb"
554 // into "Mary Had A Little Lamb"
555
556 tkstring result;
557 result.reserve(size());
558 bool pending_space = false;
559 for (const char character : *this) {
560 const bool whitespace = character == ' ' || character == '\n' || character == '\t';
561 if (whitespace) {
562 pending_space = !result.empty();
563 continue;
564 }
565 if (pending_space) result += ' ';
566 result += character;
567 pending_space = false;
568 }
569 return result;
570}
571
572bool tkstring::match(const char *_pattern) const
573{
574 // Check if pattern fit the considered string
575 // As in ls shell command the * symbol represents the non discriminant part
576 // of the pattern
577 // if no * is present in the pattern, the result correspond to TString::Contains method
578 // Example KVString st(file_R45.dat);
579 // st.Match("*") -> kTRUE
580 // st.Match("file") ->kTRUE
581 // st.Match("*file*R*") ->kTRUE
582 // etc ....
583
584 tkstring pat(_pattern);
585
586 if (!pat.contains("*")) return this->contains(pat);
587 if (pat == "*") return true;
588
589 std::vector<tkstring> tok = pat.tokenize("*");
590 int n_tok = tok.size();
591 if (!pat.begins_with("*"))
592 if (!begins_with(tok.front())) {
593 return false;
594 }
595 if (!pat.ends_with("*"))
596 if (!ends_with(tok.back())) {
597 return false;
598 }
599
600 int idx = 0, num = 0;
601 for (int ii = 0; ii < n_tok; ii += 1) {
602 idx = index(tok.at(ii), idx);
603 if (idx != -1) {
604 num += 1;
605 idx++;
606 } else break;
607 }
608 return (num == n_tok);
609}
610
616std::istream& tkstring::read_line(std::istream& _strm, bool _skip_white)
617{
618 if(_skip_white) getline(_strm >> std::ws, *this);
619 else getline(_strm, *this);
620
621 return _strm;
622}
623
625{
626 if(error.is_empty()) return -1.;
627 return error.atof()*tkstring::get_precision(val);
628}
629
643{
644 double precision = 1.0; int expo; size_t l1,l2;
645
646 l1 = st.index(".",0,tkstring::kIgnoreCase);
647 l2 = st.index("e",0,tkstring::kIgnoreCase);
648
649 if ( l1 == std::string::npos ) { // no point
650 if ( l2 == std::string::npos ) // no exponant
651 precision = 1.0;
652 else { // exponant
653 st.erase(0,l2+1);
654 expo = st.atoi();
655 precision = pow(10.,expo);
656 }
657 } else { // one point
658 if ( l2 == std::string::npos ) { // no exponant
659 expo = - (st.size() - l1 - 1);
660 precision = pow(10.0,expo);
661 }
662 else { // exponant
663 st.erase(0,l2+1);
664 expo = st.atoi();
665 expo = - (l2 - l1 - 1) + expo;
666 precision = pow(10.0,expo);
667 }
668 }
669 if ( precision < 0 ) precision = -1.0 * precision;
670
671 return precision;
672}
673
674#ifdef HAS_ROOT
675ClassImp(tkstring);
676#endif
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
Definition tkstring.h:33
tkstring extract_alpha()
Returns a tkstring composed only of the alphabetic letters of the original tkstring.
Definition tkstring.cpp:394
tkstring strip_all_extra_white_space() const
Definition tkstring.cpp:550
tkstring copy() const
Returns a copy of this string.
Definition tkstring.cpp:377
tkstring & to_lower()
Change all letters to lower case.
Definition tkstring.cpp:118
static const char * form(const char *_format,...)
Definition tkstring.cpp:438
bool is_float() const
Checks if string contains a floating point or integer number.
Definition tkstring.cpp:167
tkstring get_last_occurence(const char *_s1)
Definition tkstring.cpp:352
std::vector< tkstring > tokenize(const tkstring &_delim=" ") const
Create a vector of string separated by at least one delimiter.
Definition tkstring.cpp:292
static tkstring Form(const char *_format,...)
Definition tkstring.cpp:368
tkstring substr(size_type __pos=0, size_type __n=npos) const
Inlines.
Definition tkstring.h:160
std::vector< tkstring > tokenize_from_string(const tkstring &_delim) const
Create a vector of string separated by a full string as delimiter.
Definition tkstring.cpp:312
bool match(const char *_pattern) const
Definition tkstring.cpp:572
bool is_alpha() const
Checks whether tkstring is only composed of alphabetic letters.
Definition tkstring.cpp:427
std::istream & read_line(std::istream &_strm, bool _skip_white=true)
tkstring::read_line
Definition tkstring.cpp:616
int atoi() const
Converts a string to integer value.
Definition tkstring.cpp:210
bool ends_with(const char *_s, ECaseCompare _cmp=kExact) const
Definition tkstring.cpp:272
static double get_absolute_error(tkstring val, tkstring error)
Get absolute uncertainty from value and error strings (1.27 4 -> 0.04), returns -1 in case of empty e...
Definition tkstring.cpp:624
bool equal_to(const char *_s, ECaseCompare _cmp=kExact) const
Returns true if the string and _s are identical.
Definition tkstring.cpp:259
size_t index(const char *_s, size_t _pos=0, ECaseCompare _cmp=kExact) const
Returns the index of the substring _s.
Definition tkstring.cpp:237
tkstring remove_alpha()
Returns a tkstring composed only of the non alphabetic letters of the original tkstring.
Definition tkstring.cpp:408
tkstring & remove_all_extra_white_space()
Definition tkstring.cpp:525
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
Definition tkstring.h:184
int count_string(const tkstring &_st) const
Definition tkstring.cpp:536
bool begins_with(const char *_s, ECaseCompare _cmp=kExact) const
Definition tkstring.h:166
tkstring & capitalize()
Change first letter of string from lower to upper case.
Definition tkstring.cpp:383
static double get_precision(tkstring _st)
Extract the precision for a given ENSDF data.
Definition tkstring.cpp:642
tkstring & replace_all(const tkstring &_s1, const tkstring &_s2)
Definition tkstring.h:196
bool is_digit() const
Checks if all characters in string are digits (0-9) or whitespaces.
Definition tkstring.cpp:140
int64_t atoll() const
Converts a string to long integer value.
Definition tkstring.cpp:216
tkstring remove_last_occurence(const char *_s1)
Definition tkstring.cpp:360
double atof() const
Converts a string to double value.
Definition tkstring.cpp:226
tkstring & to_upper()
Change all letters to upper case.
Definition tkstring.cpp:124
Definition tklog.cpp:16
std::string wrap_text(const tkstring &_text, size_t _first_content_col, size_t _continuation_col, size_t _max_line_width=80)
Definition tkstring.cpp:75
tklog & error(tklog &log)
Definition tklog.h:344