diff --git a/bionetgen/modelapi/bngparser.py b/bionetgen/modelapi/bngparser.py index 94ba63e..cd54090 100644 --- a/bionetgen/modelapi/bngparser.py +++ b/bionetgen/modelapi/bngparser.py @@ -28,9 +28,49 @@ def _normalize_action_text(action: str) -> str: text = _strip_comment_outside_quotes(action) text = _collapse_unquoted_whitespace(text) text = _strip_unquoted_backslashes(text) + text = _collapse_unquoted_double_commas(text) return text.strip() +def _collapse_unquoted_double_commas(text: str) -> str: + """Collapse repeated commas that appear outside string literals.""" + out = [] + in_single = False + in_double = False + escaped = False + prev_was_comma = False + for ch in text: + if escaped: + out.append(ch) + escaped = False + prev_was_comma = False + continue + if ch == "\\" and (in_single or in_double): + out.append(ch) + escaped = True + prev_was_comma = False + continue + if ch == '"' and not in_single: + in_double = not in_double + out.append(ch) + prev_was_comma = False + continue + if ch == "'" and not in_double: + in_single = not in_single + out.append(ch) + prev_was_comma = False + continue + if ch == "," and not in_single and not in_double: + if prev_was_comma: + continue + prev_was_comma = True + out.append(ch) + continue + prev_was_comma = False + out.append(ch) + return "".join(out) + + def _strip_unquoted_backslashes(text: str) -> str: """Drop ``\\`` characters that appear outside string literals.""" return _filter_outside_quotes(text, lambda ch: ch != "\\") diff --git a/tests/test_bng_parsing.py b/tests/test_bng_parsing.py index b0d63e0..feda7f1 100644 --- a/tests/test_bng_parsing.py +++ b/tests/test_bng_parsing.py @@ -90,3 +90,20 @@ def test_action_normalization_preserves_backslashes_inside_quotes(): out = _normalize_action_text('action({arg=>"a\\b"})') assert '"a\\b"' in out + + +def test_action_normalization_collapses_unquoted_double_commas(): + from bionetgen.modelapi.bngparser import _normalize_action_text + + out = _normalize_action_text( + 'simulate({method=>"ode",t_end=>3000,n_steps=>20,,print_functions=>1})' + ) + assert ",," not in out + assert ",n_steps=>20,print_functions=>1" in out + + +def test_action_normalization_preserves_double_commas_inside_quotes(): + from bionetgen.modelapi.bngparser import _normalize_action_text + + out = _normalize_action_text('something({xs=>"0,,1,,2"})') + assert '"0,,1,,2"' in out