KaliVeda  1.13/01
Heavy-Ion Analysis Toolkit
KVString.cpp
Go to the documentation of this file.
1 //$Id: KVString.cpp,v 1.15 2008/04/04 13:08:00 franklan Exp $
2 
3 #include "KVString.h"
4 #include "Riostream.h"
5 #include "TObjString.h"
6 #include "TObjArray.h"
7 #include <list>
8 #include <stdlib.h>
9 #include <ctype.h>
10 #include <algorithm>
11 
12 #include "snprintf.h"
13 #include "TBuffer.h"
14 #include "TError.h"
15 #include "Bytes.h"
16 #include "TClass.h"
17 #include "TMath.h"
18 #include <TObject.h>
19 #include <list>
20 #include "TRandom.h"
21 
22 #ifdef R__GLOBALSTL
23 namespace std {
24  using::list;
25 }
26 #endif
28 
29 
30 #ifdef __WITHOUT_TSTRING_TOKENIZE
31 
38 
39 TObjArray* KVString::Tokenize(const TString& delim) const
40 {
41  // This function is used to isolate sequential tokens in a TString.
42  // These tokens are separated in the string by at least one of the
43  // characters in delim. The returned array contains the tokens
44  // as TObjString's. The returned array is the owner of the objects,
45  // and must be deleted by the user.
46 
47  std::list < Int_t > splitIndex;
48 
49  Int_t i, start, nrDiff = 0;
50  for (i = 0; i < delim.Length(); i++) {
51  start = 0;
52  while (start < Length()) {
53  Int_t pos = Index(delim(i), start);
54  if (pos == kNPOS)
55  break;
56  splitIndex.push_back(pos);
57  start = pos + 1;
58  }
59  if (start > 0)
60  nrDiff++;
61  }
62  splitIndex.push_back(Length());
63 
64  if (nrDiff > 1)
65  splitIndex.sort();
66 
67  TObjArray* arr = new TObjArray();
68  arr->SetOwner();
69 
70  start = -1;
71  std::list < Int_t >::const_iterator it;
72 #ifndef R__HPUX
73  for (it = splitIndex.begin(); it != splitIndex.end(); it++) {
74 #else
75  for (it = splitIndex.begin();
76  it != (std::list < Int_t >::const_iterator) splitIndex.end();
77  it++) {
78 #endif
79  Int_t stop = *it;
80  if (stop - 1 >= start + 1) {
81  TString tok = (*this)(start + 1, stop - start - 1);
82  TObjString* objstr = new TObjString(tok);
83  arr->Add(objstr);
84  }
85  start = stop;
86  }
87 
88  return arr;
89 }
90 
91 #endif
92 
93 #ifdef __WITH_KVSTRING_ISDIGIT
94 
100 
102 {
103  // Returns true if all characters in string are digits (0-9) or whitespaces,
104  // i.e. "123456" and "123 456" are both valid integer strings.
105  // Returns false in case string length is 0 or string contains other
106  // characters or only whitespace.
107 
108  const char* cp = Data();
109  Ssiz_t len = Length();
110  if (len == 0) return kFALSE;
111  Int_t b = 0, d = 0;
112  for (Ssiz_t i = 0; i < len; ++i) {
113  if (cp[i] != ' ' && !isdigit(cp[i])) return kFALSE;
114  if (cp[i] == ' ') b++;
115  if (isdigit(cp[i])) d++;
116  }
117  if (b && !d)
118  return kFALSE;
119  return kTRUE;
120 }
121 
122 #endif
123 
124 #ifdef __WITH_KVSTRING_REMOVE
125 
129 
131 {
132  // Remove char c at begin and/or end of string (like Strip() but
133  // modifies directly the string.
134  *this = Strip(st, c);
135  return *this;
136 }
137 
138 #endif
139 
140 #ifdef __WITH_KVSTRING_ATOI
141 
146 
147 Int_t KVString::Atoi() const
148 {
149  //Enhanced version of TString::Atoi().
150  //Atoi(): with string="123 456", TString::Atoi() gives value=123
151  // KVString::Atoi() gives value=123456
152 
153  Int_t end = Index(" ");
154  //if no whitespaces in string, just use atoi()
155  if (end == -1)
156  return atoi(Data());
157 
158  Int_t start = 0;
159  TString tmp;
160  while (end > -1) {
161  tmp += (*this)(start, end - start);
162  start = end + 1;
163  end = Index(" ", start);
164  }
165  end = Length();
166  tmp += (*this)(start, end - start);
167  return atoi(tmp.Data());
168 }
169 
170 #endif
171 
172 #ifdef __WITH_KVSTRING_ATOF
173 
179 
180 Double_t KVString::Atof() const
181 {
182  //Enhanced version of TString::Atof().
183  //Atof(): with string="12,34", TString::Atof() gives value=12
184  // KVString::Atof() gives value=12.34
185 
186  //look for a comma and some whitespace
187  Int_t comma = Index(",");
188  Int_t end = Index(" ");
189  //if no commas & no whitespace in string, just use atof()
190  if (comma == -1 && end == -1)
191  return atof(Data());
192  TString tmp = *this;
193  if (comma > -1) {
194  //replace comma with full stop
195  tmp.Replace(comma, 1, ".");
196  }
197  //no whitespace ?
198  if (end == -1)
199  return atof(tmp.Data());
200  //remove whitespace
201  Int_t start = 0;
202  TString tmp2;
203  while (end > -1) {
204  tmp2 += tmp(start, end - start);
205  start = end + 1;
206  end = tmp.Index(" ", start);
207  }
208  end = tmp.Length();
209  tmp2 += tmp(start, end - start);
210  return atof(tmp2.Data());
211 }
212 
213 #endif
214 
215 #ifdef __WITH_KVSTRING_ISFLOAT
216 
227 
229 {
230  //Returns kTRUE if string contains a floating point or integer number
231  // Examples of valid formats are:
232  // 64320
233  // 64 320
234  // 6 4 3 2 0
235  // 6.4320 6,4320
236  // 6.43e20 6.43E20 6,43e20
237  // 6.43e-20 6.43E-20 6,43e-20
238 
239  //we first check if we have an integer, in this case, IsDigit() will be true straight away
240  if (IsDigit()) return kTRUE;
241 
242  TString tmp = *this;
243  //now we look for occurrences of '.', ',', e', 'E', '+', '-' and replace each
244  //with ' '. if it is a floating point, IsDigit() will then return kTRUE
245  Int_t i_dot, i_e, i_plus, i_minus, i_comma;
246  i_dot = i_e = i_plus = i_minus = i_comma = -1;
247 
248  i_dot = tmp.First('.');
249  if (i_dot > -1) tmp.Replace(i_dot, 1, " ", 1);
250  i_comma = tmp.First(',');
251  if (i_comma > -1) tmp.Replace(i_comma, 1, " ", 1);
252  i_e = tmp.First('e');
253  if (i_e > -1)
254  tmp.Replace(i_e, 1, " ", 1);
255  else {
256  //try for a capital "E"
257  i_e = tmp.First('E');
258  if (i_e > -1) tmp.Replace(i_e, 1, " ", 1);
259  }
260  i_plus = tmp.First('+');
261  if (i_plus > -1) tmp.Replace(i_plus, 1, " ", 1);
262  i_minus = tmp.First('-');
263  if (i_minus > -1) tmp.Replace(i_minus, 1, " ", 1);
264 
265  //test if it is now uniquely composed of numbers
266  return tmp.IsDigit();
267 }
268 
269 #endif
270 
271 
274 
276 {
277  //Replace every occurence of 'c1' with 'c2'
278  ReplaceAll(&c1, 1, &c2, 1);
279  return (*this);
280 }
281 
282 
283 #ifdef __WITH_KVSTRING_ISWHITESPACE
284 
287 
289 {
290  //Returns kTRUE if string is empty (IsNull()) or if every character = ' '
291  return (Length() == CountChar(' '));
292 }
293 
294 #endif
295 
296 
319 
320 Int_t KVString::Sscanf(const Char_t* fmt, ...)
321 {
322  //A more strict implementation than the standard 'sscanf'
323  //We require that any characters in the format string which are not format descriptors
324  //("%d" etc.) be identical to the characters in this KVString
325  //
326  //i.e. for a string "file6.root", sscanf("file6.root", "file%d.root", &some_integer) returns 1
327  //but so does sscanf("file6.root", "file%danything_you_want_here_i_dont_care", &some_integer).
328  //
329  //Use this method when you ONLY want "file%d.root" to match "file6.root"
330  //
331  //Returns number of fields read from string
332  //
333  //HANDLED FORMAT DESCRIPTORS
334  //
335  // %d - simple integer descriptor
336  // %3d - simple integer descriptor with length - only integers of correct length accepted
337  // (leading characters may be white space, i.e. ' 4' for 4 written with '%3d')
338  // %03d - simple integer descriptor with length + zero padding - only integers of correct length accepted
339  // (leading characters may be zeroes, i.e. '004' for 4 written with '%03d')
340  // %* - just garbage, no argument required, it is not read. we ignore the rest of the string
341  // and the rest of the format. this is not counted as a field to be read. i.e. Sscanf("%*")
342  // gives 0 for any string, not because it doesn't match, but because there is nothing to read.
343 
344  va_list args;
345  va_start(args, fmt);
346 
347  Int_t str_index = 0;
348  Int_t read_items = 0;
349  Int_t fmt_index = 0;
350  const char* cp = Data();
351  Int_t int_format_length_descriptor = 0;
352  Bool_t zero_padding = kFALSE;
353 
354  while (fmt[fmt_index] != '\0') {
355 
356  if (fmt[fmt_index] == '%') {
357  //handle format descriptor
358  fmt_index++;
359  if (fmt[fmt_index] >= '0' && fmt[fmt_index] <= '9') {
360  // case of %nd or %0nd with n=some integer
361  zero_padding = (fmt[fmt_index] == '0');
362  if (zero_padding) fmt_index++;
363  // stick together all figures until 'd' (or some other non-number) is found
364  KVString length_of_number = "";
365  while (fmt[fmt_index] >= '0' && fmt[fmt_index] <= '9') {
366  length_of_number += fmt[fmt_index++];
367  }
368  int_format_length_descriptor = length_of_number.Atoi();
369  }
370  if (fmt[fmt_index] == 'd') {
371  //read an integer
372  KVString dummy;
373  if (int_format_length_descriptor) {
374  if (zero_padding) {
375  // fixed length integer with leading zeroes
376  // i.e. for %03d, '3' will be represented by '003'
377  // we must read int_format_length_descriptor consecutive integers
378  Int_t figures_read = 0;
379  while (cp[str_index] >= '0' && cp[str_index] <= '9') {
380  dummy += cp[str_index++];
381  figures_read++;
382  }
383  if (figures_read != int_format_length_descriptor) {
384  // number is not correct length, string is not good
385  va_end(args);
386  return 0;
387  }
388  else {
389  // good
390  *(va_arg(args, int*)) = dummy.Atoi();
391  fmt_index++;
392  read_items++;
393  }
394  }
395  else {
396  // fixed length integer with white-space padding
397  // i.e. for %3d, '3' will be represented by ' 3'
398  // we must read int_format_length_descriptor consecutive characters
399  // which are either white-space or numbers, at least the last one must
400  // be a number, and once we start reading numbers we cannot have any more
401  // white space
402  Bool_t no_more_whitespace = kFALSE;
403  while (int_format_length_descriptor) {
404  if (cp[str_index] == '\0') {
405  // tried to read past end of string - no good
406  va_end(args);
407  return 0;
408  }
409  if ((cp[str_index] != ' ') && (cp[str_index] < '0' || cp[str_index] > '9')) {
410  // read a non-whitespace non-number - no good
411  va_end(args);
412  return 0;
413  }
414  if ((cp[str_index] == ' ') && no_more_whitespace) {
415  // read a whitespace after starting to read numbers - no good
416  va_end(args);
417  return 0;
418  }
419  if (cp[str_index] != ' ') {
420  no_more_whitespace = kTRUE;
421  dummy += cp[str_index];
422  }
423  str_index++;
424  int_format_length_descriptor--;
425  }
426  // check we read at least one number
427  if (!no_more_whitespace) {
428  va_end(args);
429  return 0;
430  }
431  // check that next character in string is not a number
432  if (cp[str_index + 1] != '\0' && (cp[str_index + 1] < '0' || cp[str_index + 1] > '9')) {
433  va_end(args);
434  return 0;
435  }
436  // good
437  *(va_arg(args, int*)) = dummy.Atoi();
438  fmt_index++;
439  read_items++;
440 
441  }
442  }
443  else {
444  // any length of integer i.e. '%d'
445  while (cp[str_index] >= '0' && cp[str_index] <= '9')
446  dummy += cp[str_index++];
447  *(va_arg(args, int*)) = dummy.Atoi();
448  fmt_index++;
449  read_items++;
450  }
451  }
452  else if (fmt[fmt_index] == '*') {
453  //rest of string is garbage
454  va_end(args);
455  return read_items;
456  }
457  }
458  else {
459  //check character in format against string
460  if (fmt[fmt_index] != cp[str_index]) {
461  va_end(args);
462  return 0; //not the same string, return 0
463  }
464  fmt_index++;
465  str_index++;
466  }
467 
468 
469  }
470 
471  va_end(args);
472 
473  //if we haven't got to the end of the string, it must not match the format
474  if (cp[str_index] != '\0')
475  return 0;
476 
477  return read_items;
478 }
479 
480 
481 
482 
493 
495 {
496  // Check if pattern fit the considered string
497  // As in ls shell command the * symbol represents the non discriminant part
498  // of the pattern
499  // if no * is present in the pattern, the result correspond to TString::Contains method
500  // Example KVString st(file_R45.dat);
501  // st.Match("*") -> kTRUE
502  // st.Match("file") ->kTRUE
503  // st.Match("*file*R*") ->kTRUE
504  // etc ....
505  if (!pattern.Contains("*")) return this->Contains(pattern);
506  else if (pattern == "*") return kTRUE;
507  else {
508  std::unique_ptr<TObjArray> tok(pattern.Tokenize("*"));
509  Int_t n_tok = tok->GetEntries();
510  if (!pattern.BeginsWith("*"))
511  if (!BeginsWith(((TObjString*)tok->First())->GetString())) {
512  return kFALSE;
513  }
514  if (!pattern.EndsWith("*"))
515  if (!EndsWith(((TObjString*)tok->Last())->GetString())) {
516  return kFALSE;
517  }
518 
519  Int_t idx = 0, num = 0;
520  for (Int_t ii = 0; ii < n_tok; ii += 1) {
521  idx = Index(((TObjString*)tok->At(ii))->GetString(), idx);
522  if (idx != -1) {
523  num += 1;
524  idx++;
525  }
526  else break;
527  }
528  if (num == n_tok) return kTRUE;
529  else return kFALSE;
530  }
531 }
532 
533 
534 
564 
565 void KVString::Begin(TString delim) const
566 {
567  // Begin(), Next() and End() can be used to loop over items in
568  // a string separated by the delimiter character given as argument
569  // to Begin().
570  //
571  // Example:
572  //~~~~{.cpp}
573  // KVString str("First | Second | Third");
574  // str.Begin("|");
575  // while( !str.End() ){
576  // cout << str.Next().Data() << endl;
577  // }
578  //~~~~
579  // This will give the following output:
580  //~~~~
581  // First
582  // Second
583  // Third
584  //~~~~
585  // \warning If the delimiter character is not contained in the string,
586  // calling Next() will return the entire contents of the string, after
587  // which End() will return kTRUE. This allows to parse strings containing
588  // variable numbers of parameters separated by a delimiter which is only
589  // used with 2 or more parameters, i.e.:
590  //
591  //~~~~
592  // "par1|par2|par3" -> "par1" "par2" "par3"
593  // "par1" -> "par1"
594  //~~~~
595  fEndList = kFALSE;
596  fIterIndex = 0;
597  if (IsNull()) {
598  fEndList = kTRUE;
599  kObjArr.reset(nullptr);
600  }
601  else {
602  kObjArr.reset(Tokenize(delim));
603  if (!kObjArr->GetEntries()) {
604  fEndList = kTRUE;
605  kObjArr.reset(nullptr);
606  }
607  }
608 }
609 
610 
611 
633 
635 {
636  // Begin(), Next() and End() can be used to loop over items in
637  // a string separated by the delimiter character given as argument
638  // to Begin().
639  //
640  // Example:
641  //~~~~{.cpp}
642  // KVString str("First | Second | Third");
643  // str.Begin("|");
644  // while( !str.End() ){
645  // cout << str.Next().Data() << endl;
646  // }
647  //~~~~
648  //
649  // This will give the following output:
650  //
651  //~~~~
652  // First
653  // Second
654  // Third
655  //~~~~
656  return fEndList;
657 }
658 
659 
660 
694 
695 KVString KVString::Next(Bool_t strip_whitespace) const
696 {
697  // Begin(), Next() and End() can be used to loop over items in
698  // a string separated by the delimiter character given as argument
699  // to Begin().
700  //
701  // @param[in] strip_whitespace if kTRUE (default is kFALSE), any leading or trailing whitespace is removed from each item
702  // \returns next item in string separated by delimiter(s) given to Begin()
703  //
704  // Example:
705  //~~~~{.cpp}
706  // KVString str("First | Second | Third");
707  // str.Begin("|");
708  // while( !str.End() ){
709  // cout << str.Next(kTRUE).Data() << endl;
710  // }
711  //~~~~
712  //
713  // This will give the following output:
714  //
715  //~~~~
716  // First
717  // Second
718  // Third
719  //~~~~
720  //
721  // whereas if Next() is used (i.e. strip_whitespace=kFALSE),
722  // this gives:
723  //
724  //~~~~
725  // First
726  // Second
727  // Third
728  //~~~~
729 
730  KVString st;
731  if (!kObjArr.get()) return st;
732  st = ((TObjString*)kObjArr->At(fIterIndex++))->GetString();
733  fEndList = (fIterIndex == kObjArr->GetEntries());
734  if (fEndList) kObjArr.reset(nullptr);
735  if (strip_whitespace) st.Remove(kBoth, ' ');
736  return st;
737 }
738 
739 
740 
767 
768 void KVString::RBegin(TString delim) const
769 {
770  // RBegin(), RNext() and End() can be used to loop BACKWARDS over items in
771  // a string separated by the delimiter character given as argument
772  // to RBegin().
773  //
774  // Example:
775  // KVString str("First | Second | Third");
776  // str.RBegin("|");
777  // while( !str.End() ){
778  // cout << str.RNext().Data() << endl;
779  // }
780  //
781  // This will give the following output:
782  //
783  // Third
784  // Second
785  // First
786  //
787  // WARNING: If the delimiter character is not contained in the string,
788  // calling RNext() will return the entire contents of the string, after
789  // which End() will return kTRUE. This allows to parse strings containing
790  // variable numbers of parameters separated by a delimiter which is only
791  // used with 2 or more parameters, i.e.:
792  //
793  // "par1|par2|par3" -> "par3" "par2" "par1"
794  // "par1" -> "par1"
795 
796  fEndList = kFALSE;
797  fIterIndex = 0;
798  if (IsNull()) {
799  fEndList = kTRUE;
800  kObjArr.reset(nullptr);
801  }
802  else {
803  kObjArr.reset(Tokenize(delim));
804  if (!kObjArr->GetEntries()) {
805  fEndList = kTRUE;
806  kObjArr.reset(nullptr);
807  }
808  fIterIndex = kObjArr->GetEntries() - 1;
809  }
810 }
811 
812 
813 
840 
841 KVString KVString::RNext(Bool_t strip_whitespace) const
842 {
843  // RBegin(), RNext() and End() can be used to loop BACKWARDS over items in
844  // a string separated by the delimiter character given as argument
845  // to RBegin().
846  // If strip_whitespace=kTRUE (default is kFALSE), any leading or
847  // trailing whitespace is removed from each item.
848  //
849  // Example:
850  // KVString str("First | Second | Third");
851  // str.RBegin("|");
852  // while( !str.End() ){
853  // cout << str.RNext(kTRUE).Data() << endl;
854  // }
855  //
856  // This will give the following output:
857  //
858  // Third
859  // Second
860  // First
861  //
862  // whereas if RNext() is used (i.e. strip_whitespace=kFALSE),
863  // this gives:
864  //
865  // Third
866  // Second
867  // First
868 
869  KVString st;
870  if (!kObjArr.get()) return st;
871  st = ((TObjString*)kObjArr->At(fIterIndex--))->GetString();
872  fEndList = (fIterIndex == -1);
873  if (fEndList) kObjArr.reset(nullptr);
874  if (strip_whitespace) st.Remove(kBoth, ' ');
875  return st;
876 }
877 
878 
879 
885 
887 {
888  // Count the number of substrings in this string separated by the given character(s)
889  // e.g. given a string "one | two | three", GetNValues("|") returns 3
890  // Note that if the 'delim' character is not contained in the string,
891  // GetNValues() will return 1 (not 0) - see Begin().
892 
893  KVString copy(*this);
894  Int_t nn = 0;
895  copy.Begin(delim);
896  while (!copy.End()) {
897  copy.Next();
898  nn += 1;
899  }
900  return nn;
901 }
902 
903 
904 
908 
909 std::vector<KVString> KVString::Vectorize(TString delim, Bool_t strip_whitespace)
910 {
911  // Split string into components according to delimiter 'delim'
912  // See Begin()/Next()/End()
913 
914  std::vector<KVString> v;
915  Begin(delim);
916  while (!End()) {
917  v.push_back(Next(strip_whitespace));
918  }
919  return v;
920 }
921 
922 #ifdef __WITH_KVSTRING_ITOA
923 
928 
929 Bool_t KVString::IsBin() const
930 {
931  // Returns true if all characters in string are binary digits (0,1).
932  // Returns false in case string length is 0 or string contains other
933  // characters.
934 
935  const char* cp = Data();
936  Ssiz_t len = Length();
937  if (len == 0) return kFALSE;
938  for (Ssiz_t i = 0; i < len; ++i)
939  if (cp[i] != '0' && cp[i] != '1')
940  return kFALSE;
941  return kTRUE;
942 }
943 
944 
945 
950 
951 Bool_t KVString::IsOct() const
952 {
953  // Returns true if all characters in string are octal digits (0-7).
954  // Returns false in case string length is 0 or string contains other
955  // characters.
956 
957  const char* cp = Data();
958  Ssiz_t len = Length();
959  if (len == 0) return kFALSE;
960  for (Ssiz_t i = 0; i < len; ++i)
961  if (!isdigit(cp[i]) || cp[i] == '8' || cp[i] == '9')
962  return kFALSE;
963  return kTRUE;
964 }
965 
966 
967 
972 
973 Bool_t KVString::IsDec() const
974 {
975  // Returns true if all characters in string are decimal digits (0-9).
976  // Returns false in case string length is 0 or string contains other
977  // characters.
978 
979  const char* cp = Data();
980  Ssiz_t len = Length();
981  if (len == 0) return kFALSE;
982  for (Ssiz_t i = 0; i < len; ++i)
983  if (!isdigit(cp[i]))
984  return kFALSE;
985  return kTRUE;
986 }
987 
988 
989 
995 
996 Bool_t KVString::IsInBaseN(Int_t base) const
997 {
998  // Returns true if all characters in string are expressed in the base
999  // specified (range=2-36), i.e. {0,1} for base 2, {0-9,a-f,A-F} for base 16,
1000  // {0-9,a-z,A-Z} for base 36. Returns false in case string length is 0 or
1001  // string contains other characters.
1002 
1003  if (base < 2 || base > 36) {
1004  Error("KVString::IsInBaseN", "base %d is not supported. Suppported bases are {2,3,...,36}.", base);
1005  return kFALSE;
1006  }
1007  if (Length() == 0) {
1008  Error("KVString::IsInBaseN", "input string is empty.") ;
1009  return kFALSE;
1010  }
1011  KVString str = KVString(Data()) ;
1012  str.ToUpper() ;
1013  KVString str_ref0 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
1014  KVString str_ref = str_ref0 ;
1015  str_ref.Remove(base) ;
1016  Bool_t isInBase = kTRUE ;
1017  for (Int_t k = 0; k < str.Length(); k++) {
1018  if (! str_ref.Contains(str[k])) {
1019  isInBase = kFALSE ;
1020  break ;
1021  }
1022  }
1023  return (isInBase);
1024 }
1025 
1026 #endif
1027 
1037 
1039 {
1040  // Converts an Int_t to a KVString with respect to the base specified (2-36).
1041  // Thus it is an enhanced version of sprintf (adapted from versions 0.4 of
1042  // http://www.jb.man.ac.uk/~slowe/cpp/itoa.html).
1043  // Usage: the following statement produce the same output, namely "1111"
1044  // std::cout << KVString::Itoa(15,2) ;
1045  // std::cout << KVString::Itoa(0xF,2) ; /// 0x prefix to handle hex
1046  // std::cout << KVString::Itoa(017,2) ; /// 0 prefix to handle oct
1047  // In case of error returns the "!" string.
1048 
1049 #ifdef __WITH_KVSTRING_ITOA
1050  std::string buf;
1051  // check that the base if valid
1052  if (base < 2 || base > 36) {
1053  Error("KVString::Itoa", "base %d is not supported. Suppported bases are {2,3,...,36}.", base) ;
1054  return (KVString("!"));
1055  }
1056  buf.reserve(35); // Pre-allocate enough space (35=kMaxDigits)
1057  Int_t quotient = value;
1058  // Translating number to string with base:
1059  do {
1060  buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ TMath::Abs(quotient % base) ];
1061  quotient /= base;
1062  }
1063  while (quotient);
1064  // Append the negative sign
1065  if (value < 0) buf += '-';
1066  std::reverse(buf.begin(), buf.end());
1067  return (KVString(buf.data()));
1068 #else
1069  return TString::Itoa(value, base);
1070 #endif
1071 }
1072 
1073 
1074 
1080 
1082 {
1083  // Converts a UInt_t (twice the range of an Int_t) to a KVString with respect
1084  // to the base specified (2-36). Thus it is an enhanced version of sprintf
1085  // (adapted from versions 0.4 of http://www.jb.man.ac.uk/~slowe/cpp/itoa.html).
1086  // In case of error returns the "!" string.
1087 
1088 #ifdef __WITH_KVSTRING_ITOA
1089  std::string buf;
1090  // check that the base if valid
1091  if (base < 2 || base > 36) {
1092  Error("KVString::UItoa", "base %d is not supported. Suppported bases are {2,3,...,36}.", base);
1093  return (KVString("!"));
1094  }
1095  buf.reserve(35); // Pre-allocate enough space (35=kMaxDigits)
1096  UInt_t quotient = value;
1097  // Translating number to string with base:
1098  do {
1099  buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ quotient % base ];
1100  quotient /= base;
1101  }
1102  while (quotient);
1103  std::reverse(buf.begin(), buf.end());
1104  return (KVString(buf.data()));
1105 #else
1106  return TString::UItoa(value, base);
1107 #endif
1108 }
1109 
1110 
1111 
1117 
1119 {
1120  // Converts a Long64_t to a KVString with respect to the base specified (2-36).
1121  // Thus it is an enhanced version of sprintf (adapted from versions 0.4 of
1122  // http://www.jb.man.ac.uk/~slowe/cpp/itoa.html).
1123  // In case of error returns the "!" string.
1124 
1125 #ifdef __WITH_KVSTRING_ITOA
1126  std::string buf;
1127  // check that the base if valid
1128  if (base < 2 || base > 36) {
1129  Error("KVString::LLtoa", "base %d is not supported. Suppported bases are {2,3,...,36}.", base);
1130  return (KVString("!"));
1131  }
1132  buf.reserve(35); // Pre-allocate enough space (35=kMaxDigits)
1133  Long64_t quotient = value;
1134  // Translating number to string with base:
1135  do {
1136  buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ TMath::Abs(quotient % base) ];
1137  quotient /= base;
1138  }
1139  while (quotient);
1140  // Append the negative sign
1141  if (value < 0) buf += '-';
1142  std::reverse(buf.begin(), buf.end());
1143  return (KVString(buf.data()));
1144 #else
1145  return TString::LLtoa(value, base);
1146 #endif
1147 }
1148 
1149 
1150 
1156 
1158 {
1159  // Converts a ULong64_t (twice the range of an Long64_t) to a KVString with
1160  // respect to the base specified (2-36). Thus it is an enhanced version of
1161  // sprintf (adapted from versions 0.4 of http://www.jb.man.ac.uk/~slowe/cpp/itoa.html).
1162  // In case of error returns the "!" string.
1163 
1164 #ifdef __WITH_KVSTRING_ITOA
1165  std::string buf;
1166  // check that the base if valid
1167  if (base < 2 || base > 36) {
1168  Error("KVString::ULLtoa", "base %d is not supported. Suppported bases are {2,3,...,36}.", base);
1169  return (KVString("!"));
1170  }
1171  buf.reserve(35); // Pre-allocate enough space (35=kMaxDigits)
1172  ULong64_t quotient = value;
1173  // Translating number to string with base:
1174  do {
1175  buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ quotient % base ];
1176  quotient /= base;
1177  }
1178  while (quotient);
1179  std::reverse(buf.begin(), buf.end());
1180  return (KVString(buf.data()));
1181 #else
1182  return TString::ULLtoa(value, base);
1183 #endif
1184 }
1185 
1186 
1187 
1191 
1192 KVString KVString::BaseConvert(const KVString& s_in, Int_t base_in, Int_t base_out)
1193 {
1194  // Converts string from base base_in to base base_out. Supported bases
1195  // are 2-36. At most 64 bit data can be converted.
1196 
1197 #ifdef __WITH_KVSTRING_ITOA
1198  KVString s_out = "!" ; // return value in case of issue
1199  // checking base range
1200  if (base_in < 2 || base_in > 36 || base_out < 2 || base_out > 36) {
1201  Error("KVString::BaseConvert", "only bases 2-36 are supported (base_in=%d, base_out=%d).", base_in, base_out);
1202  return (s_out);
1203  }
1204  // cleaning s_in
1205  KVString s_in_ = s_in;
1206  Bool_t isSigned = kFALSE;
1207  if (s_in_[0] == '-') {
1208  isSigned = kTRUE;
1209  s_in_.Remove(0, 1);
1210  }
1211  if (!isSigned && s_in_[0] == '+') s_in_.Remove(0, 1); // !isSigned to avoid strings beginning with "-+"
1212  if (base_in == 16 && s_in_.BeginsWith("0x")) s_in_.Remove(0, 2); // removing hex prefix if any
1213  s_in_ = KVString(s_in_.Strip(KVString::kLeading, '0')); // removing leading zeros (necessary for length comparison below)
1214  // checking s_in_ is expressed in the mentionned base
1215  if (!s_in_.IsInBaseN(base_in)) {
1216  Error("KVString::BaseConvert", "s_in=\"%s\" is not in base %d", s_in.Data(), base_in);
1217  return (s_out);
1218  }
1219  // checking s_in <= 64 bits
1220  KVString s_max = KVString::ULLtoa(18446744073709551615ULL, base_in);
1221  if (s_in_.Length() > s_max.Length()) {
1222  // string comparison (s_in_>s_max) does not take care of length
1223  Error("KVString::BaseConvert", "s_in=\"%s\" > %s = 2^64-1 in base %d.", s_in.Data(), s_max.Data(), base_in);
1224  return (s_out);
1225  }
1226  else if (s_in_.Length() == s_max.Length()) {
1227  // if ( s_in_.Length() < s_max.Length() ) everything's fine
1228  s_in_.ToLower(); // s_max is lower case
1229  if (s_in_ > s_max) {
1230  // string comparison
1231  Error("KVString::BaseConvert", "s_in=\"%s\" > %s = 2^64-1 in base %d.", s_in.Data(), s_max.Data(), base_in);
1232  return (s_out);
1233  }
1234  }
1235 
1236  // computing s_out
1237  ULong64_t i = ULong64_t(strtoull(s_in.Data(), 0, base_in));
1238  s_out = KVString::ULLtoa(i, base_out);
1239  if (isSigned) s_out.Prepend("-");
1240  return (s_out);
1241 #else
1242  return TString::BaseConvert(s_in, base_in, base_out);
1243 #endif
1244 }
1245 
1246 
1247 
1252 
1254 {
1255  // Remove any superfluous whitespace (or tabs or newlines) from this string (modifies string)
1256  // i.e. transform " Mary Had\tA Little \n Laaaaaaaaaaaaaaaaaamb"
1257  // into "Mary Had A Little Lamb"
1258 
1259  Begin(" \n\t");
1260  KVString tmp;
1261  while (!End()) {
1262  if (tmp.Length()) tmp += " ";
1263  tmp += Next();
1264  }
1265  *this = tmp;
1266 }
1267 
1268 
1269 
1274 
1276 {
1277  // Remove any superfluous whitespace (or tabs or newlines) from string (does not modify string)
1278  // i.e. transform " Mary Had\tA Little \n Laaaaaaaaaaaaaaaaaamb"
1279  // into "Mary Had A Little Lamb"
1280 
1281  KVString tmp = *this;
1282  KVString tmp2;
1283  tmp.Begin(" \n\t");
1284  while (!tmp.End()) {
1285  if (tmp2.Length()) tmp2 += " ";
1286  tmp2 += tmp.Next();
1287  }
1288  return tmp2;
1289 }
1290 
1291 
1292 
1306 
1308 {
1309  // list is a collection of objects with names
1310  // this method generates a string containing all characters which appear
1311  // in every name in the list, the others are replaced by the 'bug' character.
1312  //
1313  // example:
1314  // list contains a set of TNamed with names:
1315  // run_0001.root
1316  // run_0002.root
1317  // ...
1318  // run_0099.root
1319  //
1320  // then toto.FindCommonCharacters(list) will produce toto="run_00*.root"
1321 
1322  KVString tmp;
1323  TIter next(list);
1324  TObject* o;
1325  // find differences
1326  while ((o = next())) {
1327  if (tmp == "") {
1328  tmp = o->GetName();
1329  continue;
1330  }
1331  int tmplen = tmp.Length();
1332  KVString tmp2 = o->GetName();
1333  int tmp2len = tmp2.Length();
1334  int len = TMath::Min(tmplen, tmp2len);
1335  for (int i = 0; i < len; i++) {
1336  if (tmp[i] != tmp2[i]) tmp[i] = bug;
1337  }
1338  if (tmp2len > tmplen) {
1339  tmp.Append(bug, tmp2len - tmplen);
1340  }
1341  }
1342  // replace multiple occurences of bug
1343  int tmplen = tmp.Length();
1344  *this = "";
1345  bool do_bug = false;
1346  for (int i = 0; i < tmplen; i++) {
1347  if (do_bug) {
1348  if (tmp[i] == bug) continue;
1349  else do_bug = false;
1350  }
1351  else if (tmp[i] == bug) {
1352  do_bug = true;
1353  }
1354  Append(tmp[i]);
1355  }
1356 
1357  return *this;
1358 }
1359 
1360 
1361 
1362 
1376 
1378 {
1379  // list is a collection of objects with titles
1380  // this method generates a string containing all characters which appear
1381  // in every title in the list, the others are replaced by the 'bug' character.
1382  //
1383  // example:
1384  // list contains a set of TNamed with titles:
1385  // run_0001.root
1386  // run_0002.root
1387  // ...
1388  // run_0099.root
1389  //
1390  // then toto.FindCommonCharacters(list) will produce toto="run_00*.root"
1391 
1392  KVString tmp;
1393  TIter next(list);
1394  TObject* o;
1395  // find differences
1396  while ((o = next())) {
1397  if (tmp == "") {
1398  tmp = o->GetTitle();
1399  continue;
1400  }
1401  int tmplen = tmp.Length();
1402  KVString tmp2 = o->GetTitle();
1403  int tmp2len = tmp2.Length();
1404  int len = TMath::Min(tmplen, tmp2len);
1405  for (int i = 0; i < len; i++) {
1406  if (tmp[i] != tmp2[i]) tmp[i] = bug;
1407  }
1408  if (tmp2len > tmplen) {
1409  tmp.Append(bug, tmp2len - tmplen);
1410  }
1411  }
1412  // replace multiple occurences of bug
1413  int tmplen = tmp.Length();
1414  *this = "";
1415  bool do_bug = false;
1416  for (int i = 0; i < tmplen; i++) {
1417  if (do_bug) {
1418  if (tmp[i] == bug) continue;
1419  else do_bug = false;
1420  }
1421  else if (tmp[i] == bug) {
1422  do_bug = true;
1423  }
1424  Append(tmp[i]);
1425  }
1426 
1427  return *this;
1428 }
1429 
1430 
1431 
1435 
1437 {
1438  // Generate a random sequence of upper- and lower-case letters
1439  // of given length
1440 
1441  Clear();
1442  for (Int_t i = 0; i < length; ++i) {
1443  UInt_t p = gRandom->Integer(52);
1444  if (p < 26) Append((char)p + 'A');
1445  else Append((char)(p - 26) + 'a');
1446  }
1447 }
1448 
1449 
1450 
1453 
1455 {
1456  // Change first character of string from lower to upper case
1457 
1458  if ((*this)[0] >= 'a' && (*this)[0] <= 'z')(*this)[0] -= ('a' - 'A');
1459 }
1460 
1461 
1462 
1463 
1465 
1467 {
1468  Double_t y = value;
1469  Double_t ey = error;
1470 
1471  TString sy = Format("%1.2e", y);
1472  TString sey = Format("%1.1e", ey);
1473 
1474  TString sy_dec, sy_exp, sey_dec, sey_exp;
1475  Double_t y_dec, ey_dec;
1476  Int_t y_exp, ey_exp;
1477 
1478  //Recup de la valeur y
1479  std::unique_ptr<TObjArray> loa_y(sy.Tokenize("e"));
1480 
1481  TIter next_y(loa_y.get());
1482  TObjString* os_y = 0;
1483  os_y = (TObjString*)next_y();
1484  sy_dec = os_y->GetString();
1485  os_y = (TObjString*)next_y();
1486  sy_exp = os_y->GetString();
1487 
1488  y_dec = sy_dec.Atof();
1489  y_exp = sy_exp.Atoi();
1490 
1491  //Recup de la valeur ey
1492  std::unique_ptr<TObjArray> loa_ey(sey.Tokenize("e"));
1493 
1494  TIter next_ey(loa_ey.get());
1495  TObjString* os_ey = 0;
1496 
1497  os_ey = (TObjString*)next_ey();
1498  sey_dec = os_ey->GetString();
1499 
1500  os_ey = (TObjString*)next_ey();
1501  sey_exp = os_ey->GetString();
1502 
1503  ey_dec = sey_dec.Atof();
1504  ey_exp = sey_exp.Atoi();
1505 
1506  Double_t err = ey_dec * TMath::Power(10., ey_exp - y_exp);
1507  TString s;
1508 
1509  if (!((TString)Format("%1.2g", y_dec)).Contains(".") && err >= 1) {
1510 
1511  if (!((TString)Format("%1.2g", err)).Contains(".")) {
1512  if (y_exp == ey_exp) s = Format("%1.2g.0(%g.0).10$^{%d}$", y_dec, ey_dec, y_exp);
1513  else s = Format("%1.3g.0(%g.0).10$^{%d}$", y_dec, err, y_exp);
1514  }
1515  else if (((TString)Format("%1.2g", err)) == ((TString)Format("%1.1g", err)) && ((TString)Format("%1.2g", err)).Contains(".")) {
1516  if (y_exp == ey_exp) s = Format("%1.2g.0(%g0).10$^{%d}$", y_dec, ey_dec, y_exp);
1517  else s = Format("%1.3g.0(%g0).10$^{%d}$", y_dec, err, y_exp);
1518  }
1519  else {
1520  if (y_exp == ey_exp) s = Format("%1.2g.0(%g).10$^{%d}$", y_dec, ey_dec, y_exp);
1521  else s = Format("%1.3g.0(%g).10$^{%d}$", y_dec, err, y_exp);
1522  }
1523  }
1524  else if (((TString)Format("%1.3g", y_dec)) == ((TString)Format("%1.2g", y_dec)) && ((TString)Format("%1.2g", y_dec)).Contains(".") && err < 1) {
1525 
1526  if (!((TString)Format("%1.2g", err)).Contains(".")) {
1527  if (y_exp == ey_exp) s = Format("%1.2g0(%g.0).10$^{%d}$", y_dec, ey_dec, y_exp);
1528  else s = Format("%1.3g0(%g.0).10$^{%d}$", y_dec, err, y_exp);
1529  }
1530  else if (((TString)Format("%1.2g", err)) == ((TString)Format("%1.1g", err)) && ((TString)Format("%1.2g", err)).Contains(".")) {
1531  if (y_exp == ey_exp) s = Format("%1.2g0(%g0).10$^{%d}$", y_dec, ey_dec, y_exp);
1532  else s = Format("%1.3g0(%g0).10$^{%d}$", y_dec, err, y_exp);
1533  }
1534  else {
1535  if (y_exp == ey_exp) s = Format("%1.2g0(%g).10$^{%d}$", y_dec, ey_dec, y_exp);
1536  else s = Format("%1.3g0(%g).10$^{%d}$", y_dec, err, y_exp);
1537  }
1538  }
1539  else if (!((TString)Format("%1.2g", err)).Contains(".")) {
1540  if (y_exp == ey_exp) s = Format("%1.2g(%g.0).10$^{%d}$", y_dec, ey_dec, y_exp);
1541  else s = Format("%1.3g(%g.0).10$^{%d}$", y_dec, err, y_exp);
1542  }
1543  else if (((TString)Format("%1.2g", err)) == ((TString)Format("%1.1g", err)) && ((TString)Format("%1.2g", err)).Contains(".")) {
1544  if (y_exp == ey_exp) s = Format("%1.2g(%g0).10$^{%d}$", y_dec, ey_dec, y_exp);
1545  else s = Format("%1.3g(%g0).10$^{%d}$", y_dec, err, y_exp);
1546  }
1547  else {
1548  if (y_exp == ey_exp) s = Format("%1.2g(%g).10$^{%d}$", y_dec, ey_dec, y_exp);
1549  else s = Format("%1.3g(%g).10$^{%d}$", y_dec, err, y_exp);;
1550  }
1551 
1552  s.ReplaceAll(".10$^{0}$", "");
1553  s.ReplaceAll("0)", ")");
1554 
1555  Form("%s", s.Data());
1556 }
1557 
1558 
int Int_t
unsigned int UInt_t
#define str(s)
Definition: KVBase.cpp:57
ClassImp(KVPartitionList) void KVPartitionList
Initialisation.
#define d(i)
#define b(i)
int Ssiz_t
char Char_t
const Bool_t kFALSE
bool Bool_t
double Double_t
const Bool_t kTRUE
R__EXTERN TRandom * gRandom
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition: KVString.h:72
void Begin(TString delim) const
Definition: KVString.cpp:565
std::unique_ptr< TObjArray > kObjArr
used by Next() to iterate over list
Definition: KVString.h:76
void RBegin(TString delim) const
Definition: KVString.cpp:768
void RemoveAllExtraWhiteSpace()
Definition: KVString.cpp:1253
Bool_t End() const
Definition: KVString.cpp:634
KVString Next(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:695
virtual Int_t Sscanf(const Char_t *fmt,...)
Definition: KVString.cpp:320
static KVString ULLtoa(ULong64_t value, Int_t base)
Definition: KVString.cpp:1157
static KVString LLtoa(Long64_t value, Int_t base)
Definition: KVString.cpp:1118
Bool_t fEndList
used by Next() & End() to iterate over list
Definition: KVString.h:78
void RandomLetterSequence(Int_t length)
Definition: KVString.cpp:1436
std::vector< KVString > Vectorize(TString delim, Bool_t strip_whitespace=kFALSE)
Definition: KVString.cpp:909
KVString()
Definition: KVString.h:82
virtual KVString & Substitute(const Char_t c1, const Char_t c2)
Replace every occurence of 'c1' with 'c2'.
Definition: KVString.cpp:275
KVString & FindCommonCharacters(const TCollection *, const char bug=' *')
Definition: KVString.cpp:1307
static KVString BaseConvert(const KVString &s_in, Int_t base_in, Int_t base_out)
Definition: KVString.cpp:1192
static KVString UItoa(UInt_t value, Int_t base)
Definition: KVString.cpp:1081
virtual Bool_t Match(TString pattern)
Definition: KVString.cpp:494
Int_t GetNValues(TString delim) const
Definition: KVString.cpp:886
static KVString Itoa(Int_t value, Int_t base)
Definition: KVString.cpp:1038
KVString RNext(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:841
Int_t fIterIndex
used by Next() to iterate over list
Definition: KVString.h:77
KVString & FindCommonTitleCharacters(const TCollection *, const char bug=' *')
Definition: KVString.cpp:1377
KVString StripAllExtraWhiteSpace() const
Definition: KVString.cpp:1275
void Capitalize()
Change first character of string from lower to upper case.
Definition: KVString.cpp:1454
virtual void SetOwner(Bool_t enable=kTRUE)
void Add(TObject *obj)
const TString & GetString() const
virtual const char * GetName() const
virtual const char * GetTitle() const
virtual UInt_t Integer(UInt_t imax)
static TString UItoa(UInt_t value, Int_t base)
Ssiz_t Length() const
static TString LLtoa(Long64_t value, Int_t base)
Bool_t IsDec() const
void ToLower()
Int_t Atoi() const
static const Ssiz_t kNPOS
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Double_t Atof() const
Bool_t IsFloat() const
void Clear()
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Ssiz_t First(char c) const
Bool_t IsDigit() const
Bool_t IsOct() const
TObjArray * Tokenize(const TString &delim) const
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
TString & Append(char c, Ssiz_t rep=1)
const char * Data() const
Bool_t IsBin() const
Bool_t IsNull() const
static TString BaseConvert(const TString &s_in, Int_t base_in, Int_t base_out)
static TString ULLtoa(ULong64_t value, Int_t base)
Int_t CountChar(Int_t c) const
TString & Prepend(char c, Ssiz_t rep=1)
Bool_t IsInBaseN(Int_t base) const
static TString Format(const char *fmt,...)
static TString Itoa(Int_t value, Int_t base)
Bool_t IsWhitespace() const
void Form(const char *fmt,...)
TString & Remove(EStripType s, char c)
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
TString & ReplaceAll(const char *s1, const char *s2)
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
long long Long64_t
unsigned long long ULong64_t
return c1
Double_t y[n]
Double_t ey[n]
return c2
const long double s
Definition: KVUnits.h:94
void Error(const char *location, const char *va_(fmt),...)
Double_t Min(Double_t a, Double_t b)
Double_t Power(Double_t x, Double_t y)
Double_t Abs(Double_t d)
v