I'm loading a .obj file that has lines like
vn 8.67548e-017 1 -1.55211e-016
for the vertex normals. How can I detect them and bring them to double notation?
I'm loading a .obj file that has lines like
vn 8.67548e-017 1 -1.55211e-016
for the vertex normals. How can I detect them and bring them to double notation?
A regex that would work pretty well would be:
-?[\d.]+(?:e-?\d+)?
Converting to a number can be done like this: String in scientific notation C++ to double conversion, I guess.
The regex is
-? # an optional -
[\d.]+ # a series of digits or dots (see *1)
(?: # start non capturing group
e # "e"
-? # an optional -
\d+ # digits
)? # end non-capturing group, make optional
**1) This is not 100% correct, technically there can be only one dot, and before it only one (or no) digit. But practically, this should not happen. So the regex is a good approximation and false positives should be very unlikely. Feel free to make the regex more specific.*
I tried a number of the other solutions to no avail, so I came up with this.
^(-?\d+)\.?\d+(e-|e\+|e|\d+)\d+$
Anything that matches is considered to be valid Scientific Notation.
Please note: This accepts e+
, e-
and e
; if you don't want to accept e
, use this: ^(-?\d+)\.?\d+(e-|e\+|\d+)\d+$
I'm not sure if it works for c++, but in c# you can add (?i)
between the ^
and (-
in the regex, to toggle in-line case-insensitivity. Without it, exponents declared like 1.05E+10
will fail to be recognised.
Edit: My previous regex was a little buggy, so I've replaced it with the one above.
You can identify the scientific values using: -?\d*\.?\d+e[+-]?\d+
regex.
The standard library function strtod
handles the exponential component just fine (so does atof
, but strtod
allows you to differentiate between a failed parse and parsing the value zero).
If you can be sure that the format of the double is scientific, you can try something like the following:
string inp("8.67548e-017");
istringstream str(inp);
double v;
str >> scientific >> v;
cout << "v: " << v << endl;
If you want to detect whether there is a floating point number of that format, then the regexes above will do the trick.
EDIT: the scientific
manipulator is actually not needed, when you stream in a double, it will automatically do the handling for you (whether it's fixed or scientific)
Well this is not exactly what you asked for since it isn't Perl (gak) and it is a regular definition not a regular expression, but it's what I use to recognize an extension of C floating point literals (the extension is permitting "_" in digit strings), I'm sure you can convert it to an unreadable regexp if you want:
/* floats: Follows ISO C89, except that we allow underscores */
let decimal_string = digit (underscore? digit) *
let hexadecimal_string = hexdigit (underscore? hexdigit) *
let decimal_fractional_constant =
decimal_string '.' decimal_string?
| '.' decimal_string
let hexadecimal_fractional_constant =
("0x" |"0X")
(hexadecimal_string '.' hexadecimal_string?
| '.' hexadecimal_string)
let decimal_exponent = ('E'|'e') ('+'|'-')? decimal_string
let binary_exponent = ('P'|'p') ('+'|'-')? decimal_string
let floating_suffix = 'L' | 'l' | 'F' | 'f' | 'D' | 'd'
let floating_literal =
(
decimal_fractional_constant decimal_exponent? |
hexadecimal_fractional_constant binary_exponent?
)
floating_suffix?
C format is designed for programming languages not data, so it may support things your input does not require.
For extracting numbers in scientific notation in C++ with std::regex
I normally use
((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?((e|E)((\\+|-)?)[[:digit:]]+)?
which corresponds to
((\+|-)?\d+)(\.((\d+)?))?((e|E)((\+|-)?)\d+)?
This will match any number of the form +12.3456e-78
where
+
or -
and is optionalA corresponding code for parsing might look like this:
std::regex const scientific_regex {"((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?((e|E)((\\+|-)?)[[:digit:]]+)?"};
std::string const str {"8.67548e-017 1 -1.55211e-016"};
for (auto it = std::sregex_iterator(str.begin(), str.end(), scientific_regex); it != std::sregex_iterator(); ++it) {
std::string const match {it->str()};
std::cout << match << std::endl;
}
If you want to convert the found sub-strings to a double
number std::stod
should handle the conversion correctly as already pointed out by Ben Voigt.