diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2019-09-19 16:31:48 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2019-09-19 16:33:28 +0300 |
commit | cdf56b2fade83eb8518dedcbdf137bc2d937407d (patch) | |
tree | 829557917c79a0776f642ed162a8444f668614a7 | |
parent | 7f97ceb05061fd45e49ae53e71ba9b7656cc8aab (diff) |
Fix T70050: Unable to import SVG
The issue was caused by parser being confused about ex unit which was
attempted to be parsed as an exponent.
-rw-r--r-- | io_curve_svg/svg_util.py | 82 | ||||
-rwxr-xr-x | io_curve_svg/svg_util_test.py | 5 |
2 files changed, 28 insertions, 59 deletions
diff --git a/io_curve_svg/svg_util.py b/io_curve_svg/svg_util.py index 42e900b4..bd744df5 100644 --- a/io_curve_svg/svg_util.py +++ b/io_curve_svg/svg_util.py @@ -46,10 +46,13 @@ def check_points_equal(point_a, point_b): abs(point_a[1] - point_b[1]) < 1e-6) match_number = r"-?\d+(\.\d+)?([eE][-+]?\d+)?" +match_number_optional_fractional = r"-?\d+(\.\d*)?([eE][-+]?\d+)?" match_first_comma = r"^\s*(?=,)" match_comma_pair = r",\s*(?=,)" match_last_comma = r",\s*$" +re_match_number_optional_fractional = re.compile(match_number_optional_fractional) + array_of_floats_pattern = f"({match_number})|{match_first_comma}|{match_comma_pair}|{match_last_comma}" re_array_of_floats_pattern = re.compile(array_of_floats_pattern) @@ -62,69 +65,32 @@ def parse_array_of_floats(text): return [value_to_float(v[0]) for v in elements] -def read_float(s: str, i: int = 0): +def read_float(text: str, start_index: int = 0): """ Reads floating point value from a string. Parsing starts at the given index. Returns the value itself (as a string) and index of first character after the value. """ - start = i - n = len(s) - token = '' - - # Skip leading whitespace characters - while i < n and (s[i].isspace() or s[i] == ','): - i += 1 - - if i == n: - return "0", i - - # Read sign - if s[i] == '-': - token += '-' - i += 1 - elif s[i] == '+': - i += 1 - - # Read integer part - if s[i].isdigit(): - while i < n and s[i].isdigit(): - token += s[i] - i += 1 - - # Fractional part - if i < n and s[i] == '.': - token += '.' - i += 1 - - if i < n and s[i].isdigit(): - while i < n and s[i].isdigit(): - token += s[i] - i += 1 - elif i == n or s[i].isspace() or s[i] == ',': - # Inkscape sometimes uses weird float format with missed - # fractional part after dot. Suppose zero fractional part - # for this case - pass - else: - raise Exception('Invalid float value near ' + s[start:start + 10]) - - # Degree - if i < n and (s[i] == 'e' or s[i] == 'E'): - token += s[i] - i += 1 - if s[i] == '+' or s[i] == '-': - token += s[i] - i += 1 - - if s[i].isdigit(): - while i < n and s[i].isdigit(): - token += s[i] - i += 1 - else: - raise Exception('Invalid float value near ' + s[start:start + 10]) - - return token, i + + n = len(text) + + # Skip leading whitespace characters and characters which we consider ignorable for float + # (like values separator). + while start_index < n and (text[start_index].isspace() or text[start_index] == ','): + start_index += 1 + if start_index == n: + return "0", start_index + + text_part = text[start_index:] + match = re_match_number_optional_fractional.match(text_part) + + if match is None: + raise Exception('Invalid float value near ' + text[start_index:start_index + 10]) + + token = match.group(0) + endptr = start_index + match.end(0) + + return token, endptr def parse_coord(coord, size): diff --git a/io_curve_svg/svg_util_test.py b/io_curve_svg/svg_util_test.py index 6f54d5f3..de1d9823 100755 --- a/io_curve_svg/svg_util_test.py +++ b/io_curve_svg/svg_util_test.py @@ -118,7 +118,7 @@ class ReadFloatTest(unittest.TestCase): def test_not_a_number(self): # TODO(sergey): Make this more concrete. with self.assertRaises(Exception): - value, endptr = read_float("1.2eV", 3) + read_float("1.2eV", 3) def test_missing_fractional(self): value, endptr = read_float("1.", 0) @@ -143,6 +143,9 @@ class ParseCoordTest(unittest.TestCase): def test_unit_cm(self): self.assertAlmostEqual(parse_coord("1.2cm", 200), 42.51968503937008) + def test_unit_ex(self): + self.assertAlmostEqual(parse_coord("1.2ex", 200), 1.2) + def test_unit_percentage(self): self.assertEqual(parse_coord("1.2%", 200), 2.4) |