KaliVeda  1.12/06
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  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 
561 
562 void KVString::Begin(TString delim) const
563 {
564  // Begin(), Next() and End() can be used to loop over items in
565  // a string separated by the delimiter character given as argument
566  // to Begin().
567  //
568  // Example:
569  // KVString str("First | Second | Third");
570  // str.Begin("|");
571  // while( !str.End() ){
572  // cout << str.Next().Data() << endl;
573  // }
574  //
575  // This will give the following output:
576  //
577  // First
578  // Second
579  // Third
580  //
581  // WARNING: If the delimiter character is not contained in the string,
582  // calling Next() will return the entire contents of the string, after
583  // which End() will return kTRUE. This allows to parse strings containing
584  // variable numbers of parameters separated by a delimiter which is only
585  // used with 2 or more parameters, i.e.:
586  //
587  // "par1|par2|par3" -> "par1" "par2" "par3"
588  // "par1" -> "par1"
589 
590  fEndList = kFALSE;
591  fIterIndex = 0;
592  if (IsNull()) {
593  fEndList = kTRUE;
594  kObjArr.reset(nullptr);
595  }
596  else {
597  kObjArr.reset(Tokenize(delim));
598  if (!kObjArr->GetEntries()) {
599  fEndList = kTRUE;
600  kObjArr.reset(nullptr);
601  }
602  }
603 }
604 
605 
606 
624 
626 {
627  // Begin(), Next() and End() can be used to loop over items in
628  // a string separated by the delimiter character given as argument
629  // to Begin().
630  //
631  // Example:
632  // KVString str("First | Second | Third");
633  // str.Begin("|");
634  // while( !str.End() ){
635  // cout << str.Next().Data() << endl;
636  // }
637  //
638  // This will give the following output:
639  //
640  // First
641  // Second
642  // Third
643  return fEndList;
644 }
645 
646 
647 
674 
675 KVString KVString::Next(Bool_t strip_whitespace) const
676 {
677  // Begin(), Next() and End() can be used to loop over items in
678  // a string separated by the delimiter character given as argument
679  // to Begin().
680  // If strip_whitespace=kTRUE (default is kFALSE), any leading or
681  // trailing whitespace is removed from each item.
682  //
683  // Example:
684  // KVString str("First | Second | Third");
685  // str.Begin("|");
686  // while( !str.End() ){
687  // cout << str.Next(kTRUE).Data() << endl;
688  // }
689  //
690  // This will give the following output:
691  //
692  // First
693  // Second
694  // Third
695  //
696  // whereas if Next() is used (i.e. strip_whitespace=kFALSE),
697  // this gives:
698  //
699  // First
700  // Second
701  // Third
702 
703  KVString st;
704  if (!kObjArr.get()) return st;
705  st = ((TObjString*)kObjArr->At(fIterIndex++))->GetString();
706  fEndList = (fIterIndex == kObjArr->GetEntries());
707  if (fEndList) kObjArr.reset(nullptr);
708  if (strip_whitespace) st.Remove(kBoth, ' ');
709  return st;
710 }
711 
712 
713 
740 
741 void KVString::RBegin(TString delim) const
742 {
743  // RBegin(), RNext() and End() can be used to loop BACKWARDS over items in
744  // a string separated by the delimiter character given as argument
745  // to RBegin().
746  //
747  // Example:
748  // KVString str("First | Second | Third");
749  // str.RBegin("|");
750  // while( !str.End() ){
751  // cout << str.RNext().Data() << endl;
752  // }
753  //
754  // This will give the following output:
755  //
756  // Third
757  // Second
758  // First
759  //
760  // WARNING: If the delimiter character is not contained in the string,
761  // calling RNext() will return the entire contents of the string, after
762  // which End() will return kTRUE. This allows to parse strings containing
763  // variable numbers of parameters separated by a delimiter which is only
764  // used with 2 or more parameters, i.e.:
765  //
766  // "par1|par2|par3" -> "par3" "par2" "par1"
767  // "par1" -> "par1"
768 
769  fEndList = kFALSE;
770  fIterIndex = 0;
771  if (IsNull()) {
772  fEndList = kTRUE;
773  kObjArr.reset(nullptr);
774  }
775  else {
776  kObjArr.reset(Tokenize(delim));
777  if (!kObjArr->GetEntries()) {
778  fEndList = kTRUE;
779  kObjArr.reset(nullptr);
780  }
781  fIterIndex = kObjArr->GetEntries() - 1;
782  }
783 }
784 
785 
786 
813 
814 KVString KVString::RNext(Bool_t strip_whitespace) const
815 {
816  // RBegin(), RNext() and End() can be used to loop BACKWARDS over items in
817  // a string separated by the delimiter character given as argument
818  // to RBegin().
819  // If strip_whitespace=kTRUE (default is kFALSE), any leading or
820  // trailing whitespace is removed from each item.
821  //
822  // Example:
823  // KVString str("First | Second | Third");
824  // str.RBegin("|");
825  // while( !str.End() ){
826  // cout << str.RNext(kTRUE).Data() << endl;
827  // }
828  //
829  // This will give the following output:
830  //
831  // Third
832  // Second
833  // First
834  //
835  // whereas if RNext() is used (i.e. strip_whitespace=kFALSE),
836  // this gives:
837  //
838  // Third
839  // Second
840  // First
841 
842  KVString st;
843  if (!kObjArr.get()) return st;
844  st = ((TObjString*)kObjArr->At(fIterIndex--))->GetString();
845  fEndList = (fIterIndex == -1);
846  if (fEndList) kObjArr.reset(nullptr);
847  if (strip_whitespace) st.Remove(kBoth, ' ');
848  return st;
849 }
850 
851 
852 
858 
860 {
861  // Count the number of substrings in this string separated by the given character(s)
862  // e.g. given a string "one | two | three", GetNValues("|") returns 3
863  // Note that if the 'delim' character is not contained in the string,
864  // GetNValues() will return 1 (not 0) - see Begin().
865 
866  KVString copy(*this);
867  Int_t nn = 0;
868  copy.Begin(delim);
869  while (!copy.End()) {
870  copy.Next();
871  nn += 1;
872  }
873  return nn;
874 }
875 
876 
877 
881 
882 std::vector<KVString> KVString::Vectorize(TString delim, Bool_t strip_whitespace)
883 {
884  // Split string into components according to delimiter 'delim'
885  // See Begin()/Next()/End()
886 
887  std::vector<KVString> v;
888  Begin(delim);
889  while (!End()) {
890  v.push_back(Next(strip_whitespace));
891  }
892  return v;
893 }
894 
895 #ifdef __WITH_KVSTRING_ITOA
896 
901 
902 Bool_t KVString::IsBin() const
903 {
904  // Returns true if all characters in string are binary digits (0,1).
905  // Returns false in case string length is 0 or string contains other
906  // characters.
907 
908  const char* cp = Data();
909  Ssiz_t len = Length();
910  if (len == 0) return kFALSE;
911  for (Ssiz_t i = 0; i < len; ++i)
912  if (cp[i] != '0' && cp[i] != '1')
913  return kFALSE;
914  return kTRUE;
915 }
916 
917 
918 
923 
924 Bool_t KVString::IsOct() const
925 {
926  // Returns true if all characters in string are octal digits (0-7).
927  // Returns false in case string length is 0 or string contains other
928  // characters.
929 
930  const char* cp = Data();
931  Ssiz_t len = Length();
932  if (len == 0) return kFALSE;
933  for (Ssiz_t i = 0; i < len; ++i)
934  if (!isdigit(cp[i]) || cp[i] == '8' || cp[i] == '9')
935  return kFALSE;
936  return kTRUE;
937 }
938 
939 
940 
945 
946 Bool_t KVString::IsDec() const
947 {
948  // Returns true if all characters in string are decimal digits (0-9).
949  // Returns false in case string length is 0 or string contains other
950  // characters.
951 
952  const char* cp = Data();
953  Ssiz_t len = Length();
954  if (len == 0) return kFALSE;
955  for (Ssiz_t i = 0; i < len; ++i)
956  if (!isdigit(cp[i]))
957  return kFALSE;
958  return kTRUE;
959 }
960 
961 
962 
968 
969 Bool_t KVString::IsInBaseN(Int_t base) const
970 {
971  // Returns true if all characters in string are expressed in the base
972  // specified (range=2-36), i.e. {0,1} for base 2, {0-9,a-f,A-F} for base 16,
973  // {0-9,a-z,A-Z} for base 36. Returns false in case string length is 0 or
974  // string contains other characters.
975 
976  if (base < 2 || base > 36) {
977  Error("KVString::IsInBaseN", "base %d is not supported. Suppported bases are {2,3,...,36}.", base);
978  return kFALSE;
979  }
980  if (Length() == 0) {
981  Error("KVString::IsInBaseN", "input string is empty.") ;
982  return kFALSE;
983  }
984  KVString str = KVString(Data()) ;
985  str.ToUpper() ;
986  KVString str_ref0 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
987  KVString str_ref = str_ref0 ;
988  str_ref.Remove(base) ;
989  Bool_t isInBase = kTRUE ;
990  for (Int_t k = 0; k < str.Length(); k++) {
991  if (! str_ref.Contains(str[k])) {
992  isInBase = kFALSE ;
993  break ;
994  }
995  }
996  return (isInBase);
997 }
998 
999 #endif
1000 
1010 
1012 {
1013  // Converts an Int_t to a KVString with respect to the base specified (2-36).
1014  // Thus it is an enhanced version of sprintf (adapted from versions 0.4 of
1015  // http://www.jb.man.ac.uk/~slowe/cpp/itoa.html).
1016  // Usage: the following statement produce the same output, namely "1111"
1017  // std::cout << KVString::Itoa(15,2) ;
1018  // std::cout << KVString::Itoa(0xF,2) ; /// 0x prefix to handle hex
1019  // std::cout << KVString::Itoa(017,2) ; /// 0 prefix to handle oct
1020  // In case of error returns the "!" string.
1021 
1022 #ifdef __WITH_KVSTRING_ITOA
1023  std::string buf;
1024  // check that the base if valid
1025  if (base < 2 || base > 36) {
1026  Error("KVString::Itoa", "base %d is not supported. Suppported bases are {2,3,...,36}.", base) ;
1027  return (KVString("!"));
1028  }
1029  buf.reserve(35); // Pre-allocate enough space (35=kMaxDigits)
1030  Int_t quotient = value;
1031  // Translating number to string with base:
1032  do {
1033  buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ TMath::Abs(quotient % base) ];
1034  quotient /= base;
1035  }
1036  while (quotient);
1037  // Append the negative sign
1038  if (value < 0) buf += '-';
1039  std::reverse(buf.begin(), buf.end());
1040  return (KVString(buf.data()));
1041 #else
1042  return TString::Itoa(value, base);
1043 #endif
1044 }
1045 
1046 
1047 
1053 
1055 {
1056  // Converts a UInt_t (twice the range of an Int_t) to a KVString with respect
1057  // to the base specified (2-36). Thus it is an enhanced version of sprintf
1058  // (adapted from versions 0.4 of http://www.jb.man.ac.uk/~slowe/cpp/itoa.html).
1059  // In case of error returns the "!" string.
1060 
1061 #ifdef __WITH_KVSTRING_ITOA
1062  std::string buf;
1063  // check that the base if valid
1064  if (base < 2 || base > 36) {
1065  Error("KVString::UItoa", "base %d is not supported. Suppported bases are {2,3,...,36}.", base);
1066  return (KVString("!"));
1067  }
1068  buf.reserve(35); // Pre-allocate enough space (35=kMaxDigits)
1069  UInt_t quotient = value;
1070  // Translating number to string with base:
1071  do {
1072  buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ quotient % base ];
1073  quotient /= base;
1074  }
1075  while (quotient);
1076  std::reverse(buf.begin(), buf.end());
1077  return (KVString(buf.data()));
1078 #else
1079  return TString::UItoa(value, base);
1080 #endif
1081 }
1082 
1083 
1084 
1090 
1092 {
1093  // Converts a Long64_t to a KVString with respect to the base specified (2-36).
1094  // Thus it is an enhanced version of sprintf (adapted from versions 0.4 of
1095  // http://www.jb.man.ac.uk/~slowe/cpp/itoa.html).
1096  // In case of error returns the "!" string.
1097 
1098 #ifdef __WITH_KVSTRING_ITOA
1099  std::string buf;
1100  // check that the base if valid
1101  if (base < 2 || base > 36) {
1102  Error("KVString::LLtoa", "base %d is not supported. Suppported bases are {2,3,...,36}.", base);
1103  return (KVString("!"));
1104  }
1105  buf.reserve(35); // Pre-allocate enough space (35=kMaxDigits)
1106  Long64_t quotient = value;
1107  // Translating number to string with base:
1108  do {
1109  buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ TMath::Abs(quotient % base) ];
1110  quotient /= base;
1111  }
1112  while (quotient);
1113  // Append the negative sign
1114  if (value < 0) buf += '-';
1115  std::reverse(buf.begin(), buf.end());
1116  return (KVString(buf.data()));
1117 #else
1118  return TString::LLtoa(value, base);
1119 #endif
1120 }
1121 
1122 
1123 
1129 
1131 {
1132  // Converts a ULong64_t (twice the range of an Long64_t) to a KVString with
1133  // respect to the base specified (2-36). Thus it is an enhanced version of
1134  // sprintf (adapted from versions 0.4 of http://www.jb.man.ac.uk/~slowe/cpp/itoa.html).
1135  // In case of error returns the "!" string.
1136 
1137 #ifdef __WITH_KVSTRING_ITOA
1138  std::string buf;
1139  // check that the base if valid
1140  if (base < 2 || base > 36) {
1141  Error("KVString::ULLtoa", "base %d is not supported. Suppported bases are {2,3,...,36}.", base);
1142  return (KVString("!"));
1143  }
1144  buf.reserve(35); // Pre-allocate enough space (35=kMaxDigits)
1145  ULong64_t quotient = value;
1146  // Translating number to string with base:
1147  do {
1148  buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ quotient % base ];
1149  quotient /= base;
1150  }
1151  while (quotient);
1152  std::reverse(buf.begin(), buf.end());
1153  return (KVString(buf.data()));
1154 #else
1155  return TString::ULLtoa(value, base);
1156 #endif
1157 }
1158 
1159 
1160 
1164 
1165 KVString KVString::BaseConvert(const KVString& s_in, Int_t base_in, Int_t base_out)
1166 {
1167  // Converts string from base base_in to base base_out. Supported bases
1168  // are 2-36. At most 64 bit data can be converted.
1169 
1170 #ifdef __WITH_KVSTRING_ITOA
1171  KVString s_out = "!" ; // return value in case of issue
1172  // checking base range
1173  if (base_in < 2 || base_in > 36 || base_out < 2 || base_out > 36) {
1174  Error("KVString::BaseConvert", "only bases 2-36 are supported (base_in=%d, base_out=%d).", base_in, base_out);
1175  return (s_out);
1176  }
1177  // cleaning s_in
1178  KVString s_in_ = s_in;
1179  Bool_t isSigned = kFALSE;
1180  if (s_in_[0] == '-') {
1181  isSigned = kTRUE;
1182  s_in_.Remove(0, 1);
1183  }
1184  if (!isSigned && s_in_[0] == '+') s_in_.Remove(0, 1); // !isSigned to avoid strings beginning with "-+"
1185  if (base_in == 16 && s_in_.BeginsWith("0x")) s_in_.Remove(0, 2); // removing hex prefix if any
1186  s_in_ = KVString(s_in_.Strip(KVString::kLeading, '0')); // removing leading zeros (necessary for length comparison below)
1187  // checking s_in_ is expressed in the mentionned base
1188  if (!s_in_.IsInBaseN(base_in)) {
1189  Error("KVString::BaseConvert", "s_in=\"%s\" is not in base %d", s_in.Data(), base_in);
1190  return (s_out);
1191  }
1192  // checking s_in <= 64 bits
1193  KVString s_max = KVString::ULLtoa(18446744073709551615ULL, base_in);
1194  if (s_in_.Length() > s_max.Length()) {
1195  // string comparison (s_in_>s_max) does not take care of length
1196  Error("KVString::BaseConvert", "s_in=\"%s\" > %s = 2^64-1 in base %d.", s_in.Data(), s_max.Data(), base_in);
1197  return (s_out);
1198  }
1199  else if (s_in_.Length() == s_max.Length()) {
1200  // if ( s_in_.Length() < s_max.Length() ) everything's fine
1201  s_in_.ToLower(); // s_max is lower case
1202  if (s_in_ > s_max) {
1203  // string comparison
1204  Error("KVString::BaseConvert", "s_in=\"%s\" > %s = 2^64-1 in base %d.", s_in.Data(), s_max.Data(), base_in);
1205  return (s_out);
1206  }
1207  }
1208 
1209  // computing s_out
1210  ULong64_t i = ULong64_t(strtoull(s_in.Data(), 0, base_in));
1211  s_out = KVString::ULLtoa(i, base_out);
1212  if (isSigned) s_out.Prepend("-");
1213  return (s_out);
1214 #else
1215  return TString::BaseConvert(s_in, base_in, base_out);
1216 #endif
1217 }
1218 
1219 
1220 
1225 
1227 {
1228  // Remove any superfluous whitespace (or tabs or newlines) from this string (modifies string)
1229  // i.e. transform " Mary Had\tA Little \n Laaaaaaaaaaaaaaaaaamb"
1230  // into "Mary Had A Little Lamb"
1231 
1232  Begin(" \n\t");
1233  KVString tmp;
1234  while (!End()) {
1235  if (tmp.Length()) tmp += " ";
1236  tmp += Next();
1237  }
1238  *this = tmp;
1239 }
1240 
1241 
1242 
1247 
1249 {
1250  // Remove any superfluous whitespace (or tabs or newlines) from string (does not modify string)
1251  // i.e. transform " Mary Had\tA Little \n Laaaaaaaaaaaaaaaaaamb"
1252  // into "Mary Had A Little Lamb"
1253 
1254  KVString tmp = *this;
1255  KVString tmp2;
1256  tmp.Begin(" \n\t");
1257  while (!tmp.End()) {
1258  if (tmp2.Length()) tmp2 += " ";
1259  tmp2 += tmp.Next();
1260  }
1261  return tmp2;
1262 }
1263 
1264 
1265 
1279 
1281 {
1282  // list is a collection of objects with names
1283  // this method generates a string containing all characters which appear
1284  // in every name in the list, the others are replaced by the 'bug' character.
1285  //
1286  // example:
1287  // list contains a set of TNamed with names:
1288  // run_0001.root
1289  // run_0002.root
1290  // ...
1291  // run_0099.root
1292  //
1293  // then toto.FindCommonCharacters(list) will produce toto="run_00*.root"
1294 
1295  KVString tmp;
1296  TIter next(list);
1297  TObject* o;
1298  // find differences
1299  while ((o = next())) {
1300  if (tmp == "") {
1301  tmp = o->GetName();
1302  continue;
1303  }
1304  int tmplen = tmp.Length();
1305  KVString tmp2 = o->GetName();
1306  int tmp2len = tmp2.Length();
1307  int len = TMath::Min(tmplen, tmp2len);
1308  for (int i = 0; i < len; i++) {
1309  if (tmp[i] != tmp2[i]) tmp[i] = bug;
1310  }
1311  if (tmp2len > tmplen) {
1312  tmp.Append(bug, tmp2len - tmplen);
1313  }
1314  }
1315  // replace multiple occurences of bug
1316  int tmplen = tmp.Length();
1317  *this = "";
1318  bool do_bug = false;
1319  for (int i = 0; i < tmplen; i++) {
1320  if (do_bug) {
1321  if (tmp[i] == bug) continue;
1322  else do_bug = false;
1323  }
1324  else if (tmp[i] == bug) {
1325  do_bug = true;
1326  }
1327  Append(tmp[i]);
1328  }
1329 
1330  return *this;
1331 }
1332 
1333 
1334 
1335 
1349 
1351 {
1352  // list is a collection of objects with titles
1353  // this method generates a string containing all characters which appear
1354  // in every title in the list, the others are replaced by the 'bug' character.
1355  //
1356  // example:
1357  // list contains a set of TNamed with titles:
1358  // run_0001.root
1359  // run_0002.root
1360  // ...
1361  // run_0099.root
1362  //
1363  // then toto.FindCommonCharacters(list) will produce toto="run_00*.root"
1364 
1365  KVString tmp;
1366  TIter next(list);
1367  TObject* o;
1368  // find differences
1369  while ((o = next())) {
1370  if (tmp == "") {
1371  tmp = o->GetTitle();
1372  continue;
1373  }
1374  int tmplen = tmp.Length();
1375  KVString tmp2 = o->GetTitle();
1376  int tmp2len = tmp2.Length();
1377  int len = TMath::Min(tmplen, tmp2len);
1378  for (int i = 0; i < len; i++) {
1379  if (tmp[i] != tmp2[i]) tmp[i] = bug;
1380  }
1381  if (tmp2len > tmplen) {
1382  tmp.Append(bug, tmp2len - tmplen);
1383  }
1384  }
1385  // replace multiple occurences of bug
1386  int tmplen = tmp.Length();
1387  *this = "";
1388  bool do_bug = false;
1389  for (int i = 0; i < tmplen; i++) {
1390  if (do_bug) {
1391  if (tmp[i] == bug) continue;
1392  else do_bug = false;
1393  }
1394  else if (tmp[i] == bug) {
1395  do_bug = true;
1396  }
1397  Append(tmp[i]);
1398  }
1399 
1400  return *this;
1401 }
1402 
1403 
1404 
1408 
1410 {
1411  // Generate a random sequence of upper- and lower-case letters
1412  // of given length
1413 
1414  Clear();
1415  for (Int_t i = 0; i < length; ++i) {
1416  UInt_t p = gRandom->Integer(52);
1417  if (p < 26) Append((char)p + 'A');
1418  else Append((char)(p - 26) + 'a');
1419  }
1420 }
1421 
1422 
1423 
1426 
1428 {
1429  // Change first character of string from lower to upper case
1430 
1431  if ((*this)[0] >= 'a' && (*this)[0] <= 'z')(*this)[0] -= ('a' - 'A');
1432 }
1433 
1434 
1435 
1436 
1438 
1440 {
1441  Double_t y = value;
1442  Double_t ey = error;
1443 
1444  TString sy = Format("%1.2e", y);
1445  TString sey = Format("%1.1e", ey);
1446 
1447  TString sy_dec, sy_exp, sey_dec, sey_exp;
1448  Double_t y_dec, ey_dec;
1449  Int_t y_exp, ey_exp;
1450 
1451  //Recup de la valeur y
1452  unique_ptr<TObjArray> loa_y(sy.Tokenize("e"));
1453 
1454  TIter next_y(loa_y.get());
1455  TObjString* os_y = 0;
1456  os_y = (TObjString*)next_y();
1457  sy_dec = os_y->GetString();
1458  os_y = (TObjString*)next_y();
1459  sy_exp = os_y->GetString();
1460 
1461  y_dec = sy_dec.Atof();
1462  y_exp = sy_exp.Atoi();
1463 
1464  //Recup de la valeur ey
1465  unique_ptr<TObjArray> loa_ey(sey.Tokenize("e"));
1466 
1467  TIter next_ey(loa_ey.get());
1468  TObjString* os_ey = 0;
1469 
1470  os_ey = (TObjString*)next_ey();
1471  sey_dec = os_ey->GetString();
1472 
1473  os_ey = (TObjString*)next_ey();
1474  sey_exp = os_ey->GetString();
1475 
1476  ey_dec = sey_dec.Atof();
1477  ey_exp = sey_exp.Atoi();
1478 
1479  Double_t err = ey_dec * TMath::Power(10., ey_exp - y_exp);
1480  TString s;
1481 
1482  if (!((TString)Format("%1.2g", y_dec)).Contains(".") && err >= 1) {
1483 
1484  if (!((TString)Format("%1.2g", err)).Contains(".")) {
1485  if (y_exp == ey_exp) s = Format("%1.2g.0(%g.0).10$^{%d}$", y_dec, ey_dec, y_exp);
1486  else s = Format("%1.3g.0(%g.0).10$^{%d}$", y_dec, err, y_exp);
1487  }
1488  else if (((TString)Format("%1.2g", err)) == ((TString)Format("%1.1g", err)) && ((TString)Format("%1.2g", err)).Contains(".")) {
1489  if (y_exp == ey_exp) s = Format("%1.2g.0(%g0).10$^{%d}$", y_dec, ey_dec, y_exp);
1490  else s = Format("%1.3g.0(%g0).10$^{%d}$", y_dec, err, y_exp);
1491  }
1492  else {
1493  if (y_exp == ey_exp) s = Format("%1.2g.0(%g).10$^{%d}$", y_dec, ey_dec, y_exp);
1494  else s = Format("%1.3g.0(%g).10$^{%d}$", y_dec, err, y_exp);
1495  }
1496  }
1497  else if (((TString)Format("%1.3g", y_dec)) == ((TString)Format("%1.2g", y_dec)) && ((TString)Format("%1.2g", y_dec)).Contains(".") && err < 1) {
1498 
1499  if (!((TString)Format("%1.2g", err)).Contains(".")) {
1500  if (y_exp == ey_exp) s = Format("%1.2g0(%g.0).10$^{%d}$", y_dec, ey_dec, y_exp);
1501  else s = Format("%1.3g0(%g.0).10$^{%d}$", y_dec, err, y_exp);
1502  }
1503  else if (((TString)Format("%1.2g", err)) == ((TString)Format("%1.1g", err)) && ((TString)Format("%1.2g", err)).Contains(".")) {
1504  if (y_exp == ey_exp) s = Format("%1.2g0(%g0).10$^{%d}$", y_dec, ey_dec, y_exp);
1505  else s = Format("%1.3g0(%g0).10$^{%d}$", y_dec, err, y_exp);
1506  }
1507  else {
1508  if (y_exp == ey_exp) s = Format("%1.2g0(%g).10$^{%d}$", y_dec, ey_dec, y_exp);
1509  else s = Format("%1.3g0(%g).10$^{%d}$", y_dec, err, y_exp);
1510  }
1511  }
1512  else if (!((TString)Format("%1.2g", err)).Contains(".")) {
1513  if (y_exp == ey_exp) s = Format("%1.2g(%g.0).10$^{%d}$", y_dec, ey_dec, y_exp);
1514  else s = Format("%1.3g(%g.0).10$^{%d}$", y_dec, err, y_exp);
1515  }
1516  else if (((TString)Format("%1.2g", err)) == ((TString)Format("%1.1g", err)) && ((TString)Format("%1.2g", err)).Contains(".")) {
1517  if (y_exp == ey_exp) s = Format("%1.2g(%g0).10$^{%d}$", y_dec, ey_dec, y_exp);
1518  else s = Format("%1.3g(%g0).10$^{%d}$", y_dec, err, y_exp);
1519  }
1520  else {
1521  if (y_exp == ey_exp) s = Format("%1.2g(%g).10$^{%d}$", y_dec, ey_dec, y_exp);
1522  else s = Format("%1.3g(%g).10$^{%d}$", y_dec, err, y_exp);;
1523  }
1524 
1525  s.ReplaceAll(".10$^{0}$", "");
1526  s.ReplaceAll("0)", ")");
1527 
1528  Form("%s", s.Data());
1529 }
1530 
1531 
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:562
unique_ptr< TObjArray > kObjArr
used by Next() to iterate over list
Definition: KVString.h:76
void RBegin(TString delim) const
Definition: KVString.cpp:741
void RemoveAllExtraWhiteSpace()
Definition: KVString.cpp:1226
Bool_t End() const
Definition: KVString.cpp:625
KVString Next(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:675
virtual Int_t Sscanf(const Char_t *fmt,...)
Definition: KVString.cpp:320
static KVString ULLtoa(ULong64_t value, Int_t base)
Definition: KVString.cpp:1130
static KVString LLtoa(Long64_t value, Int_t base)
Definition: KVString.cpp:1091
Bool_t fEndList
used by Next() & End() to iterate over list
Definition: KVString.h:78
void RandomLetterSequence(Int_t length)
Definition: KVString.cpp:1409
std::vector< KVString > Vectorize(TString delim, Bool_t strip_whitespace=kFALSE)
Definition: KVString.cpp:882
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:1280
static KVString BaseConvert(const KVString &s_in, Int_t base_in, Int_t base_out)
Definition: KVString.cpp:1165
static KVString UItoa(UInt_t value, Int_t base)
Definition: KVString.cpp:1054
virtual Bool_t Match(TString pattern)
Definition: KVString.cpp:494
Int_t GetNValues(TString delim) const
Definition: KVString.cpp:859
static KVString Itoa(Int_t value, Int_t base)
Definition: KVString.cpp:1011
KVString RNext(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:814
Int_t fIterIndex
used by Next() to iterate over list
Definition: KVString.h:77
KVString & FindCommonTitleCharacters(const TCollection *, const char bug=' *')
Definition: KVString.cpp:1350
KVString StripAllExtraWhiteSpace() const
Definition: KVString.cpp:1248
void Capitalize()
Change first character of string from lower to upper case.
Definition: KVString.cpp:1427
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