__AUTHOR__ = "Cuesta0113"
class Letter:
def __init__(self, s:str):
self.name = s[0]
self.isPrime = s[-1] == "'"
self.value = ord(s[0]) * 10 + (1 if self.isPrime else 0)
def __lt__(self, other: "Letter"):
return self.value < other.value
def __str__(self):
return self.name + ("'" if self.isPrime else "")
class Term:
def __init__(self, letters: list[Letter]):
self.letters = letters
def __lt__(self, other: "Term"):
length = min(len(self.letters), len(other.letters))
for i in range(length):
if self.letters[i] > other.letters[i]: return True
if self.letters[i] < other.letters[i]: return False
return len(self.letters) > len(other.letters)
def __str__(self):
return "".join([str(letter) for letter in self.letters])
class Validator:
def autoSort(self, expression: str) -> list[list[Letter]]:
# exclude the space
expression = expression.replace(" ", "").replace(" ", "")
# fix the typing error
expression = expression.replace("+", "+")\
.replace("'", "'")\
.replace("`", "'")\
.replace("’", "'")\
.replace("‘", "'")\
.replace("‵", "'")\
.replace("(", "")\
.replace(")", "")\
.replace("(", "")\
.replace(")", "")\
# split SOP format by '+'
tmp = expression.split("+")
terms: list[list[Letter]] = []
for term in tmp:
terms.append([])
# find next letter
for i, ch in enumerate(term):
if ch.isalpha():
terms[-1].append(Letter(term[i:i+2]))
# sort each term internally
for term in terms:
term.sort()
# wrap each term with class
terms = [Term(term) for term in terms]
# sort each term externally, a solid bubble sort
for i in range(len(terms)):
for j in range(len(terms)):
if terms[i] > terms[j]: terms[i], terms[j] = terms[j], terms[i]
return terms
def isRT(a: str, b:str, term:str):
pass
if __name__ == "__main__":
v = Validator()
result = []
for term in v.autoSort(input("Please Enter The Expression In SOP Format: ")):
result.append(str(term))
print("+".join(result))
"""
TEST CASES:
A‵BD' + A B D’ + BCD + ABC‘ + AB'D
=> ABC'+ABD'+AB'D+A'BD'+BCD
A’BD` + DBC + ABC‵ + AB‘D+A'A
=> AA'+ABC'+AB'D+A'BD'+BCD
BB'B+BA+A'A+A
=> A+AA'+AB+BBB'
"""
X19BVVRIT1JfXyA9ICJDdWVzdGEwMTEzIgoKY2xhc3MgTGV0dGVyOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIHM6c3RyKToKICAgICAgICBzZWxmLm5hbWUgPSBzWzBdCiAgICAgICAgc2VsZi5pc1ByaW1lID0gc1stMV0gPT0gIiciCiAgICAgICAgc2VsZi52YWx1ZSA9IG9yZChzWzBdKSAqIDEwICsgKDEgaWYgc2VsZi5pc1ByaW1lIGVsc2UgMCkKICAgIAogICAgZGVmIF9fbHRfXyhzZWxmLCBvdGhlcjogIkxldHRlciIpOgogICAgICAgIHJldHVybiBzZWxmLnZhbHVlIDwgb3RoZXIudmFsdWUKCiAgICBkZWYgX19zdHJfXyhzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5uYW1lICsgKCInIiBpZiBzZWxmLmlzUHJpbWUgZWxzZSAiIikKCmNsYXNzIFRlcm06CiAgICBkZWYgX19pbml0X18oc2VsZiwgbGV0dGVyczogbGlzdFtMZXR0ZXJdKToKICAgICAgICBzZWxmLmxldHRlcnMgPSBsZXR0ZXJzCiAgICAKICAgIGRlZiBfX2x0X18oc2VsZiwgb3RoZXI6ICJUZXJtIik6CiAgICAgICAgbGVuZ3RoID0gbWluKGxlbihzZWxmLmxldHRlcnMpLCBsZW4ob3RoZXIubGV0dGVycykpCiAgICAgICAgZm9yIGkgaW4gcmFuZ2UobGVuZ3RoKToKICAgICAgICAgICAgaWYgc2VsZi5sZXR0ZXJzW2ldID4gb3RoZXIubGV0dGVyc1tpXTogcmV0dXJuIFRydWUKICAgICAgICAgICAgaWYgc2VsZi5sZXR0ZXJzW2ldIDwgb3RoZXIubGV0dGVyc1tpXTogcmV0dXJuIEZhbHNlCiAgICAgICAgcmV0dXJuIGxlbihzZWxmLmxldHRlcnMpID4gbGVuKG90aGVyLmxldHRlcnMpCgogICAgZGVmIF9fc3RyX18oc2VsZik6CiAgICAgICAgcmV0dXJuICIiLmpvaW4oW3N0cihsZXR0ZXIpIGZvciBsZXR0ZXIgaW4gc2VsZi5sZXR0ZXJzXSkKCmNsYXNzIFZhbGlkYXRvcjoKICAgIGRlZiBhdXRvU29ydChzZWxmLCBleHByZXNzaW9uOiBzdHIpIC0+IGxpc3RbbGlzdFtMZXR0ZXJdXToKICAgICAgICAjIGV4Y2x1ZGUgdGhlIHNwYWNlCiAgICAgICAgZXhwcmVzc2lvbiA9IGV4cHJlc3Npb24ucmVwbGFjZSgiICIsICIiKS5yZXBsYWNlKCLjgIAiLCAiIikKCiAgICAgICAgIyBmaXggdGhlIHR5cGluZyBlcnJvcgogICAgICAgIGV4cHJlc3Npb24gPSBleHByZXNzaW9uLnJlcGxhY2UoIu+8iyIsICIrIilcCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgi77yHIiwgIiciKVwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKCJgIiwgIiciKVwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKCLigJkiLCAiJyIpXAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoIuKAmCIsICInIilcCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgi4oC1IiwgIiciKVwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKCLvvIgiLCAiIilcCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgi77yJIiwgIiIpXAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoIigiLCAiIilcCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgiKSIsICIiKVwKCiAgICAgICAgIyBzcGxpdCBTT1AgZm9ybWF0IGJ5ICcrJwogICAgICAgIHRtcCA9IGV4cHJlc3Npb24uc3BsaXQoIisiKQogICAgICAgIHRlcm1zOiBsaXN0W2xpc3RbTGV0dGVyXV0gPSBbXQogICAgICAgIGZvciB0ZXJtIGluIHRtcDoKICAgICAgICAgICAgdGVybXMuYXBwZW5kKFtdKQogICAgICAgICAgICAjIGZpbmQgbmV4dCBsZXR0ZXIKICAgICAgICAgICAgZm9yIGksIGNoIGluIGVudW1lcmF0ZSh0ZXJtKToKICAgICAgICAgICAgICAgIGlmIGNoLmlzYWxwaGEoKToKICAgICAgICAgICAgICAgICAgICB0ZXJtc1stMV0uYXBwZW5kKExldHRlcih0ZXJtW2k6aSsyXSkpCgogICAgICAgICMgc29ydCBlYWNoIHRlcm0gaW50ZXJuYWxseQogICAgICAgIGZvciB0ZXJtIGluIHRlcm1zOgogICAgICAgICAgICB0ZXJtLnNvcnQoKQogICAgICAgIAogICAgICAgICMgd3JhcCBlYWNoIHRlcm0gd2l0aCBjbGFzcwogICAgICAgIHRlcm1zID0gW1Rlcm0odGVybSkgZm9yIHRlcm0gaW4gdGVybXNdCiAgICAgICAgCiAgICAgICAgIyBzb3J0IGVhY2ggdGVybSBleHRlcm5hbGx5LCBhIHNvbGlkIGJ1YmJsZSBzb3J0CiAgICAgICAgZm9yIGkgaW4gcmFuZ2UobGVuKHRlcm1zKSk6CiAgICAgICAgICAgIGZvciBqIGluIHJhbmdlKGxlbih0ZXJtcykpOgogICAgICAgICAgICAgICAgaWYgdGVybXNbaV0gPiB0ZXJtc1tqXTogdGVybXNbaV0sIHRlcm1zW2pdID0gdGVybXNbal0sIHRlcm1zW2ldCgogICAgICAgIHJldHVybiB0ZXJtcwogICAgCiAgICBkZWYgaXNSVChhOiBzdHIsIGI6c3RyLCB0ZXJtOnN0cik6CiAgICAgICAgcGFzcwoKCgppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOgogICAgdiA9IFZhbGlkYXRvcigpCiAgICByZXN1bHQgPSBbXQogICAgZm9yIHRlcm0gaW4gdi5hdXRvU29ydChpbnB1dCgiUGxlYXNlIEVudGVyIFRoZSBFeHByZXNzaW9uIEluIFNPUCBGb3JtYXQ6ICIpKToKICAgICAgICByZXN1bHQuYXBwZW5kKHN0cih0ZXJtKSkKICAgIHByaW50KCIrIi5qb2luKHJlc3VsdCkpCgoiIiIKVEVTVCBDQVNFUzoKCkHigLVCRO+8hyArICBBICAgQiAgIETigJkgICArIEJDRCArIEFCQ+KAmCArIEFCJ0QKPT4gQUJDJytBQkQnK0FCJ0QrQSdCRCcrQkNECgpB4oCZQkRgICsgREJDIO+8iyBBQkPigLUgKyBBQuKAmEQrQSdBCj0+IEFBJytBQkMnK0FCJ0QrQSdCRCcrQkNECgpCQidCK0JBK0EnQStBCj0+IEErQUEnK0FCK0JCQicKIiIi