@@ -52,73 +52,98 @@ namespace Common {
5252
5353 /* * Common::FitsKeys::get_keytype *******************************************/
5454 /* *
55- * @fn get_keytype
5655 * @brief return the keyword type based on the keyvalue
5756 * @param std::string value
58- * @return std:: string type: "BOOL", "STRING", "DOUBLE", "INT"
57+ * @return string { "BOOL", "STRING", "DOUBLE", "FLOAT", " INT", "LONG" }
5958 *
60- * This function looks at the contents of the value string to determine if it
61- * contains an INT, DOUBLE, BOOL or STRING, and returns a string identifying the type.
62- * That type is used in FITS_file::add_user_key() for adding keywords to the header.
59+ * This function looks at the contents of the value string to determine if
60+ * it contains an INT, DOUBLE, FLOAT, BOOL or STRING, and returns a string
61+ * identifying the type. That type is used in FITS_file::add_user_key()
62+ * for adding keywords to the header.
63+ *
64+ * To differentiate between double and float, the keyvalue string must end
65+ * with an "f", as in "3.14f" which returns "FLOAT" or "3.14" which returns
66+ * "DOUBLE". Decimal point is required ("1f" is not a float but "1.0f" is)
67+ *
68+ * To differentiate between int and long, keyvalue string must end with "l"
69+ * as in "100l" which returns "LONG" or "100" which returns "INT". Since a
70+ * long can't have a decimal, using 'l' with a decimal point is a string.
6371 *
6472 */
6573 std::string FitsKeys::get_keytype (std::string keyvalue) {
6674 std::size_t pos (0 );
6775
76+ // If it's empty then what else can it be but string
77+ if ( keyvalue.empty () ) return std::string (" STRING" );
78+
6879 // if the entire string is either (exactly) T or F then it's a boolean
6980 if (keyvalue == " T" || keyvalue == " F" ) {
7081 return std::string (" BOOL" );
7182 }
7283
7384 // skip the whitespaces
74- pos = keyvalue.find_first_not_of (' ' );
75- if (pos == keyvalue.size ()) return std::string (" STRING" ); // all spaces, so it's a string
76-
77- // check the significand
78- if (keyvalue[pos] == ' +' || keyvalue[pos] == ' -' ) ++pos; // skip the sign if exist
79-
80- // count the number of digits and number of decimal points
81- int n_nm, n_pt;
82- for (n_nm = 0 , n_pt = 0 ; std::isdigit (keyvalue[pos]) || keyvalue[pos] == ' .' ; ++pos) {
83- keyvalue[pos] == ' .' ? ++n_pt : ++n_nm;
84- }
85-
86- if (n_pt > 1 || n_nm < 1 || pos < keyvalue.size ()) {
87- // no more than one point, no numbers, or a non-digit character
88- return std::string (" STRING" ); // then it's a string
89- }
90-
91- // skip the trailing whitespaces
92- while (keyvalue[pos] == ' ' ) {
93- ++pos;
85+ if (keyvalue.find_first_not_of (' ' ) != std::string::npos) {
86+ pos = keyvalue.find_first_not_of (' ' );
9487 }
88+ if (pos == keyvalue.size ()) return std::string (" STRING" ); // all spaces, so it's a string
9589
96- std::string check_type;
97-
98- if (pos == keyvalue.size ()) {
99- // If it's an INT or DOUBLE, don't return that type until it has been checked, below
100- //
101- if (keyvalue.find (" ." ) == std::string::npos) // all numbers and no decimals, it's an integer
102- check_type = " INT" ;
103- else // otherwise numbers with a decimal, it's a float
104- check_type = " DOUBLE" ;
105- } else return std::string (" STRING" ); // lastly, must be a string
90+ // remove sign if it exists
91+ if (keyvalue[pos] == ' +' || keyvalue[pos] == ' -' ) keyvalue.erase (0 ,1 );
10692
107- // If it's an INT or a DOUBLE then try to convert the value to INT or DOUBLE.
108- // If that conversion fails then set the type to STRING.
93+ // count the different types of characters
94+ //
95+ // number of decimal points
96+ auto n_pt = std::count (keyvalue.begin (), keyvalue.end (), ' .' );
97+ // number of numerics
98+ auto n_nm = std::count_if (keyvalue.begin (), keyvalue.end (), [](unsigned char c) {
99+ return std::isdigit (c);
100+ } );
101+ // number of string chars, non-numerics, non-decimals
102+ auto n_ch = std::count_if (keyvalue.begin (), keyvalue.end (), [](unsigned char c) {
103+ return (!std::isdigit (c) && c!=' .' );
104+ } );
105+
106+ // number of decimals points, numeric and non-numeric chars determines the type
107+ // verify by trying to convert to that type and return string on conversion failure
109108 //
110109 try {
111- if (check_type == " INT" ) std::stoi (keyvalue);
112- if (check_type == " DOUBLE" ) std::stod (keyvalue);
113- } catch (std::invalid_argument &) {
110+ // no numbers or more than one decimal point can't be any type of number, so string
111+ if ( n_nm==0 || n_pt > 1 ) {
114112 return std::string (" STRING" );
115- }
116- catch (std::out_of_range &) {
113+ }
114+ else
115+ // at least one digit, exactly one decimal point and only and last character is "f" is a float
116+ if ( n_nm > 0 && n_pt==1 && n_ch==1 && keyvalue.back ()==' f' ) {
117+ std::stof (keyvalue);
118+ return std::string (" FLOAT" );
119+ }
120+ else
121+ // at least one digit, exactly one decimal point and no chars is double
122+ if ( n_nm > 0 && n_pt==1 && n_ch==0 ) {
123+ std::stod (keyvalue);
124+ return std::string (" DOUBLE" );
125+ }
126+ else
127+ // at least one digit, no decimal point and no chars is int
128+ if ( n_nm > 0 && n_pt==0 && n_ch==0 ) {
129+ std::stoi (keyvalue);
130+ return std::string (" INT" );
131+ }
132+ else
133+ // at least one digit, no decimal point and only and last char is "l" is long
134+ if ( n_nm > 0 && n_pt==0 && n_ch==1 && keyvalue.back ()==' l' ) {
135+ std::stol (keyvalue);
136+ return std::string (" LONG" );
137+ }
138+ else
139+ // what else can it be but string
117140 return std::string (" STRING" );
118141 }
119- return check_type;
142+ catch (const std::exception &) {
143+ // any numeric conversion failure sets type as string
144+ return std::string (" STRING" );
145+ }
120146 }
121-
122147 /* * Common::FitsKeys::get_keytype *******************************************/
123148
124149
@@ -230,6 +255,19 @@ namespace Common {
230255 this ->keydb [keyword].keyvalue = keyvalue;
231256 this ->keydb [keyword].keycomment = keycomment;
232257
258+ // long and float are designated by a modifier char which must be removed
259+ //
260+ if (this ->keydb [keyword].keytype ==" LONG" ) {
261+ if (!this ->keydb [keyword].keyvalue .empty () && this ->keydb [keyword].keyvalue .back ()==' l' ) {
262+ this ->keydb [keyword].keyvalue .pop_back ();
263+ }
264+ }
265+ if (this ->keydb [keyword].keytype ==" FLOAT" ) {
266+ if (!this ->keydb [keyword].keyvalue .empty () && this ->keydb [keyword].keyvalue .back ()==' f' ) {
267+ this ->keydb [keyword].keyvalue .pop_back ();
268+ }
269+ }
270+
233271#ifdef LOGLEVEL_DEBUG
234272 message.str (" " ); message << " [DEBUG] added key: " << keyword << " =" << keyvalue << " (" << this ->keydb [keyword].keytype << " ) // " << keycomment;
235273 logwrite ( function, message.str () );
0 commit comments