Skip to content
Snippets Groups Projects
Commit cdf56b2f authored by Sergey Sharybin's avatar Sergey Sharybin
Browse files

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.
parent 7f97ceb0
No related branches found
No related tags found
No related merge requests found
......@@ -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):
......
......@@ -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)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment