From 1afa386404d35634182600f7347035396fa96192 Mon Sep 17 00:00:00 2001 From: paul019 <39464035+paul019@users.noreply.github.com> Date: Thu, 11 Apr 2024 23:32:35 +0200 Subject: [PATCH 01/18] Remove spaces in units --- src/api/console_stringifier.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index a1b9a980..fd795e71 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -34,7 +34,8 @@ def _modify_unit(self, unit: str) -> str: Returns the modified unit. """ unit = ( - unit.replace(r"\squared", "^2") + unit.replace(" ", "") + .replace(r"\squared", "^2") .replace(r"\cubed", "^3") .replace("\\per\\", "/") .replace(r"\per", "/") From 297e2b626d141012941e871647e54ddc7015f807 Mon Sep 17 00:00:00 2001 From: paul019 <39464035+paul019@users.noreply.github.com> Date: Thu, 11 Apr 2024 23:40:10 +0200 Subject: [PATCH 02/18] Detect percent as unit in console stringifier --- src/api/console_stringifier.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index fd795e71..914cdbe3 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -37,6 +37,7 @@ def _modify_unit(self, unit: str) -> str: unit.replace(" ", "") .replace(r"\squared", "^2") .replace(r"\cubed", "^3") + .replace("\\percent", "\\%") .replace("\\per\\", "/") .replace(r"\per", "/") .replace("\\", " ") From f08047df7c85fed6fa8ac028f7a6ad09a21014a9 Mon Sep 17 00:00:00 2001 From: paul019 <39464035+paul019@users.noreply.github.com> Date: Fri, 12 Apr 2024 00:26:37 +0200 Subject: [PATCH 03/18] Add small lexer to parse units with per --- src/api/console_stringifier.py | 70 +++++++++++++++++++++++++++------- tests/playground.py | 8 +++- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index 914cdbe3..c42fb120 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -1,3 +1,4 @@ +import re from domain.result import Result from application.stringifier import Stringifier @@ -33,18 +34,61 @@ def _modify_unit(self, unit: str) -> str: """ Returns the modified unit. """ - unit = ( - unit.replace(" ", "") - .replace(r"\squared", "^2") - .replace(r"\cubed", "^3") - .replace("\\percent", "\\%") - .replace("\\per\\", "/") - .replace(r"\per", "/") - .replace("\\", " ") - .strip() - ) - - if unit[0] == "/": - unit = f"1{unit}" + + # Detect "\squared" etc.: + unit = unit.replace(r"\squared", "^2").replace(r"\cubed", "^3") + unit = re.sub(r"(\s+)\^", "^", unit) + + # Detect special units: + unit = unit.replace(r"\percent", r"\%").replace(r"\degree", "°") + + # Detect "/": + unit = unit.replace("/", " / ") + + # Iterate over unit parts: + unit_parts = re.split(r"\\|\s", unit) + numerator_parts = [] + denominator_parts = [] + is_next_part_in_denominator = False + + for unit_part in unit_parts: + # Skip empty parts: + if unit_part == "": + continue + + # If next part is a denominator part: + if unit_part == "/" or unit_part == "per": + is_next_part_in_denominator = True + continue + + # Add part to numerator or denominator: + if is_next_part_in_denominator: + denominator_parts.append(unit_part) + is_next_part_in_denominator = False + else: + numerator_parts.append(unit_part) + + # Assemble unit: + unit = "" + + # Handle empty unit: + if len(numerator_parts) == 0 and len(denominator_parts) == 0: + return "" + + # Numerator: + if len(numerator_parts) == 0: + unit += "1" + elif len(numerator_parts) == 1 or len(denominator_parts) == 0: + unit += " ".join(numerator_parts) + else: + unit += f"({' '.join(numerator_parts)})" + + # Denominator: + if len(denominator_parts) > 0: + unit += "/" + if len(denominator_parts) == 1: + unit += denominator_parts[0] + else: + unit += f"({' '.join(denominator_parts)})" return unit diff --git a/tests/playground.py b/tests/playground.py index 2f28ad52..ac0353e0 100644 --- a/tests/playground.py +++ b/tests/playground.py @@ -47,7 +47,13 @@ wiz.res("h", 42, 13.0, 24.0) wiz.res("h&", 42, 13.0, 24.0) wiz.res("i", Decimal("42.0e-30"), Decimal("0.1e-31"), r"\m") -wiz.res("i", Decimal("42.0e-30"), Decimal("0.1e-31"), Decimal("0.05e-31"), r"\m\per\s\squared") +wiz.res( + "i", + Decimal("42.0e-30"), + Decimal("0.1e-31"), + Decimal("0.05e-31"), + r"\m\per\s\squared\newton\per\kg", +) wiz.res("j", 0.009, None, None, 2) # wiz.res("k", 1.55, 0.0, r"\tesla") # -> uncertainty must be positive From f0cd95dc49dd52e9b66db611b2882bd46212533a Mon Sep 17 00:00:00 2001 From: paul019 <39464035+paul019@users.noreply.github.com> Date: Fri, 12 Apr 2024 11:33:34 +0200 Subject: [PATCH 04/18] Fix consider-using-in --- src/api/console_stringifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index c42fb120..1ccc01a6 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -57,7 +57,7 @@ def _modify_unit(self, unit: str) -> str: continue # If next part is a denominator part: - if unit_part == "/" or unit_part == "per": + if unit_part in ("/", "per"): is_next_part_in_denominator = True continue From 6d78fe2fd48624c66a66ddee712fb740214ee632 Mon Sep 17 00:00:00 2001 From: paul019 <39464035+paul019@users.noreply.github.com> Date: Sun, 21 Apr 2024 22:53:48 +0200 Subject: [PATCH 05/18] Remove colons at the end of comments --- src/api/console_stringifier.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index 1ccc01a6..8dc9eb74 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -35,47 +35,47 @@ def _modify_unit(self, unit: str) -> str: Returns the modified unit. """ - # Detect "\squared" etc.: + # Detect "\squared" etc. unit = unit.replace(r"\squared", "^2").replace(r"\cubed", "^3") unit = re.sub(r"(\s+)\^", "^", unit) - # Detect special units: + # Detect special units unit = unit.replace(r"\percent", r"\%").replace(r"\degree", "°") - # Detect "/": + # Detect "/" unit = unit.replace("/", " / ") - # Iterate over unit parts: + # Iterate over unit parts unit_parts = re.split(r"\\|\s", unit) numerator_parts = [] denominator_parts = [] is_next_part_in_denominator = False for unit_part in unit_parts: - # Skip empty parts: + # Skip empty parts if unit_part == "": continue - # If next part is a denominator part: + # If next part is a denominator part if unit_part in ("/", "per"): is_next_part_in_denominator = True continue - # Add part to numerator or denominator: + # Add part to numerator or denominator if is_next_part_in_denominator: denominator_parts.append(unit_part) is_next_part_in_denominator = False else: numerator_parts.append(unit_part) - # Assemble unit: + # Assemble unit unit = "" - # Handle empty unit: + # Handle empty unit if len(numerator_parts) == 0 and len(denominator_parts) == 0: return "" - # Numerator: + # Numerator if len(numerator_parts) == 0: unit += "1" elif len(numerator_parts) == 1 or len(denominator_parts) == 0: @@ -83,7 +83,7 @@ def _modify_unit(self, unit: str) -> str: else: unit += f"({' '.join(numerator_parts)})" - # Denominator: + # Denominator if len(denominator_parts) > 0: unit += "/" if len(denominator_parts) == 1: From 4f731e68a308f7901a292e9c6dcd2ae69ed64a6b Mon Sep 17 00:00:00 2001 From: paul019 <39464035+paul019@users.noreply.github.com> Date: Sun, 21 Apr 2024 23:00:24 +0200 Subject: [PATCH 06/18] Add separator to special degree symbol --- src/api/console_stringifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index 8dc9eb74..bab6ccf8 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -40,7 +40,7 @@ def _modify_unit(self, unit: str) -> str: unit = re.sub(r"(\s+)\^", "^", unit) # Detect special units - unit = unit.replace(r"\percent", r"\%").replace(r"\degree", "°") + unit = unit.replace(r"\percent", r"\%").replace(r"\degree", r"\°") # Detect "/" unit = unit.replace("/", " / ") From 8e7bb5eeca54d467f509bde0a560507ff8637167 Mon Sep 17 00:00:00 2001 From: paul019 <39464035+paul019@users.noreply.github.com> Date: Sun, 21 Apr 2024 23:02:20 +0200 Subject: [PATCH 07/18] Rename variable --- src/api/console_stringifier.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index bab6ccf8..fd8e6312 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -69,7 +69,7 @@ def _modify_unit(self, unit: str) -> str: numerator_parts.append(unit_part) # Assemble unit - unit = "" + modified_unit = "" # Handle empty unit if len(numerator_parts) == 0 and len(denominator_parts) == 0: @@ -77,18 +77,18 @@ def _modify_unit(self, unit: str) -> str: # Numerator if len(numerator_parts) == 0: - unit += "1" + modified_unit += "1" elif len(numerator_parts) == 1 or len(denominator_parts) == 0: - unit += " ".join(numerator_parts) + modified_unit += " ".join(numerator_parts) else: - unit += f"({' '.join(numerator_parts)})" + modified_unit += f"({' '.join(numerator_parts)})" # Denominator if len(denominator_parts) > 0: - unit += "/" + modified_unit += "/" if len(denominator_parts) == 1: - unit += denominator_parts[0] + modified_unit += denominator_parts[0] else: - unit += f"({' '.join(denominator_parts)})" + modified_unit += f"({' '.join(denominator_parts)})" - return unit + return modified_unit From 497dfee85ae21522b71d6605897a9d98855e2a3a Mon Sep 17 00:00:00 2001 From: paul019 <39464035+paul019@users.noreply.github.com> Date: Sun, 21 Apr 2024 23:06:43 +0200 Subject: [PATCH 08/18] Split white spaces greedily --- src/api/console_stringifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index fd8e6312..bdc6c5b3 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -46,7 +46,7 @@ def _modify_unit(self, unit: str) -> str: unit = unit.replace("/", " / ") # Iterate over unit parts - unit_parts = re.split(r"\\|\s", unit) + unit_parts = re.split(r"[\\|\s]+", unit) numerator_parts = [] denominator_parts = [] is_next_part_in_denominator = False From dbe18f193848653021d9ed5ab0f006bf6f5f8c86 Mon Sep 17 00:00:00 2001 From: Splines Date: Wed, 14 Aug 2024 11:07:42 +0200 Subject: [PATCH 09/18] Add 1/% unit to playground --- tests/playground.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/playground.py b/tests/playground.py index ac0353e0..538cb308 100644 --- a/tests/playground.py +++ b/tests/playground.py @@ -35,6 +35,8 @@ wiz.res("a911", 1.05, r"\mm\s\per\N\kg") # wiz.res("a911", "1.052", 0.25, r"\mm\s\per\N\kg") +wiz.res("a_unit_parsing", "1.0", r"\per\percent") + wiz.res("1 b", 1.0, 0.01, r"\per\mm\cubed") # wiz.config(decimal_places=-1, sigfigs_fallback=3) From e9a0d82b3429930565c64d82cb8a8d4d8a6829a3 Mon Sep 17 00:00:00 2001 From: Splines Date: Wed, 14 Aug 2024 11:17:14 +0200 Subject: [PATCH 10/18] Simplify if conditions in unit handling --- src/api/console_stringifier.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index bdc6c5b3..d10f5d34 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -72,19 +72,19 @@ def _modify_unit(self, unit: str) -> str: modified_unit = "" # Handle empty unit - if len(numerator_parts) == 0 and len(denominator_parts) == 0: + if not numerator_parts and not denominator_parts: return "" # Numerator - if len(numerator_parts) == 0: + if not numerator_parts: modified_unit += "1" - elif len(numerator_parts) == 1 or len(denominator_parts) == 0: + elif len(numerator_parts) == 1 or not denominator_parts: modified_unit += " ".join(numerator_parts) else: modified_unit += f"({' '.join(numerator_parts)})" # Denominator - if len(denominator_parts) > 0: + if denominator_parts: modified_unit += "/" if len(denominator_parts) == 1: modified_unit += denominator_parts[0] From e23767806c33bdefa174d33b123d90726a1eb22a Mon Sep 17 00:00:00 2001 From: Splines Date: Wed, 14 Aug 2024 11:17:29 +0200 Subject: [PATCH 11/18] Add "only numerator units" to playground tests --- tests/playground.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/playground.py b/tests/playground.py index 538cb308..a30716ad 100644 --- a/tests/playground.py +++ b/tests/playground.py @@ -36,6 +36,7 @@ # wiz.res("a911", "1.052", 0.25, r"\mm\s\per\N\kg") wiz.res("a_unit_parsing", "1.0", r"\per\percent") +wiz.res("a_unit_parsing_only_numerator", "1.0", r"\m\N\kg") wiz.res("1 b", 1.0, 0.01, r"\per\mm\cubed") From 64b7d84d8d5da2491248d601d8b4c171bab5975d Mon Sep 17 00:00:00 2001 From: Splines Date: Wed, 14 Aug 2024 11:33:29 +0200 Subject: [PATCH 12/18] Remove all whitespace characters in unit string --- src/api/console_stringifier.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index d10f5d34..277a578b 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -35,9 +35,11 @@ def _modify_unit(self, unit: str) -> str: Returns the modified unit. """ + # Remove all whitespace characters (space, tab, newline etc.) + unit = "".join(unit.split()) + # Detect "\squared" etc. unit = unit.replace(r"\squared", "^2").replace(r"\cubed", "^3") - unit = re.sub(r"(\s+)\^", "^", unit) # Detect special units unit = unit.replace(r"\percent", r"\%").replace(r"\degree", r"\°") From cf26dda2a61fa4b98e3119ec51fe8c74b65d2835 Mon Sep 17 00:00:00 2001 From: Splines Date: Wed, 14 Aug 2024 11:33:36 +0200 Subject: [PATCH 13/18] Add more unit tests to playground --- tests/playground.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/playground.py b/tests/playground.py index a30716ad..d5c96641 100644 --- a/tests/playground.py +++ b/tests/playground.py @@ -34,9 +34,11 @@ wiz.res("a911", 1.05, r"\mm\s\per\N\kg") # wiz.res("a911", "1.052", 0.25, r"\mm\s\per\N\kg") - +wiz.res("a911_2", 1.05, r"\mm\s\per(\N\kg)") wiz.res("a_unit_parsing", "1.0", r"\per\percent") wiz.res("a_unit_parsing_only_numerator", "1.0", r"\m\N\kg") +wiz.res("a_unit_squared", "1.0", r"\m \squared") +wiz.res("a_unit_custom_slash", "1.0", r"\m\squared/\s") wiz.res("1 b", 1.0, 0.01, r"\per\mm\cubed") From 6d901302a81a7d0d13b03e294d136308f78a0e97 Mon Sep 17 00:00:00 2001 From: Splines Date: Wed, 11 Sep 2024 11:17:17 +0200 Subject: [PATCH 14/18] Strip whitespaces around parentheses --- src/api/console_stringifier.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index 785a6a9f..2b55db3c 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -93,4 +93,8 @@ def _modify_unit(self, unit: str) -> str: else: modified_unit += f"({' '.join(denominator_parts)})" + modified_unit = self.strip_whitespaces_around_parentheses(modified_unit) return modified_unit + + def strip_whitespaces_around_parentheses(self, string: str) -> str: + return string.replace(" (", "(").replace("( ", "(").replace(" )", ")").replace(") ", ")") From 9be9b2718373c33b0825799aba71bb412f6f386b Mon Sep 17 00:00:00 2001 From: Splines Date: Wed, 11 Sep 2024 14:38:16 +0200 Subject: [PATCH 15/18] Replace `per` by `/` in console --- src/api/console_stringifier.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index 2b55db3c..3bc4df0e 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -94,7 +94,24 @@ def _modify_unit(self, unit: str) -> str: modified_unit += f"({' '.join(denominator_parts)})" modified_unit = self.strip_whitespaces_around_parentheses(modified_unit) + modified_unit = self.replace_per_by_symbol(modified_unit) + return modified_unit def strip_whitespaces_around_parentheses(self, string: str) -> str: return string.replace(" (", "(").replace("( ", "(").replace(" )", ")").replace(") ", ")") + + def replace_per_by_symbol(self, string: str) -> str: + """ + Replaces all occurrences of `per` with `/`. + + This might be necessary due to limitations of the above parsing method + where `per(` is recognized as a single token. For a proper parser, we + would have to deal with parentheses in a more sophisticated way. As this + is not the scope of this project for now, we just do a simple replacement + of the `per` that slipped through the above logic. + + Note that at this point, `\percent` was already replaced by `%`, so + we can safely replace all occurrences of "per" with "/". + """ + return string.replace("per", " / ") From 772e86d4f535d10b90a35098574239b285e033a7 Mon Sep 17 00:00:00 2001 From: Splines Date: Wed, 11 Sep 2024 14:38:30 +0200 Subject: [PATCH 16/18] Add more examples for parentheses to playground --- tests/playground.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/playground.py b/tests/playground.py index 835becf2..fd9bc804 100644 --- a/tests/playground.py +++ b/tests/playground.py @@ -35,6 +35,8 @@ wiz.res("a911", 1.05, unit=r"\mm\s\per\N\kg") # wiz.res("a911", "1.052", 0.25, r"\mm\s\per\N\kg") wiz.res("a911_2", 1.05, unit=r"\mm\s\per(\N\kg)") +wiz.res("more parentheses", 1.05, unit=r"\mm\s\per((\N\kg))") +wiz.res("wrong parentheses", 1.05, unit=r"\mm\s\per(((\N\kg)\T") wiz.res("a_unit_parsing", "1.0", unit=r"\per\percent") wiz.res("a_unit_parsing_only_numerator", "1.0", unit=r"\m\N\kg") wiz.res("a_unit_squared", "1.0", unit=r"\m \squared") From 01afd94f56ab07e5b2af44f4681be36bc9fd2e6d Mon Sep 17 00:00:00 2001 From: Splines Date: Wed, 11 Sep 2024 14:38:40 +0200 Subject: [PATCH 17/18] Add TODO note for docs (console output) --- TODO.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TODO.md b/TODO.md index 15c58d03..3aa4bf91 100644 --- a/TODO.md +++ b/TODO.md @@ -16,6 +16,8 @@ - Suggest some good initial configuration for Jupyter notebook, e.g. `print_auto=True` and `ignore_result_overwrite=True`. - Naming: we call it "uncertainty". Give a hint that others might also call it "error" interchangeably. - Jupyter Notebook tip to avoid +- Add warning that users should not rely on console stringified output for further processing since that might change more often in the future, e.g. better formatting of units or whitespaces etc. Only rely on the final LaTeX output written to the external file. + ``` From 41eda66ac4def811cbc746c4f10891a22eefcc0c Mon Sep 17 00:00:00 2001 From: Splines Date: Wed, 11 Sep 2024 14:55:17 +0200 Subject: [PATCH 18/18] Fix anomalous backlash in string --- src/api/console_stringifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/console_stringifier.py b/src/api/console_stringifier.py index 3bc4df0e..ca8f67fa 100644 --- a/src/api/console_stringifier.py +++ b/src/api/console_stringifier.py @@ -111,7 +111,7 @@ def replace_per_by_symbol(self, string: str) -> str: is not the scope of this project for now, we just do a simple replacement of the `per` that slipped through the above logic. - Note that at this point, `\percent` was already replaced by `%`, so + Note that at this point, `percent` was already replaced by `%`, so we can safely replace all occurrences of "per" with "/". """ return string.replace("per", " / ")