diff --git a/modules/fbs-core/math-parser/src/main/antlr/de/thm/ii/fbs/mathParser/Math.g4 b/modules/fbs-core/math-parser/src/main/antlr/de/thm/ii/fbs/mathParser/Math.g4 index 88c597e29..aa5122160 100644 --- a/modules/fbs-core/math-parser/src/main/antlr/de/thm/ii/fbs/mathParser/Math.g4 +++ b/modules/fbs-core/math-parser/src/main/antlr/de/thm/ii/fbs/mathParser/Math.g4 @@ -26,6 +26,7 @@ mulFactor : expo // higher presedence! ; expo : expo ' '* EXP ' '* SUB? factor + | expo unicode_expo | factor ; @@ -34,6 +35,8 @@ factor : LEFT? OPENING_ROUND_BRACKET ' '* expr ' '* RIGHT? CLOSING_ROUND_BR | (NUMBER|VAR) ; +unicode_expo : UNICODE_EXPO+ + ; NUMBER: FULL DECIMAL?; FULL: [0-9]+; @@ -64,3 +67,4 @@ OPENING_SQUARE_BRACKET: '['; CLOSING_SQUARE_BRACKET: ']'; LEFT: '\\left'; RIGHT: '\\right'; +UNICODE_EXPO: '⁰'|'¹'|'²'|'³'|'⁴'|'⁵'|'⁶'|'⁷'|'⁸'|'⁹'; diff --git a/modules/fbs-core/math-parser/src/main/kotlin/de/thm/ii/fbs/mathParser/AstBuilder.kt b/modules/fbs-core/math-parser/src/main/kotlin/de/thm/ii/fbs/mathParser/AstBuilder.kt index 2b6639043..fce795458 100644 --- a/modules/fbs-core/math-parser/src/main/kotlin/de/thm/ii/fbs/mathParser/AstBuilder.kt +++ b/modules/fbs-core/math-parser/src/main/kotlin/de/thm/ii/fbs/mathParser/AstBuilder.kt @@ -73,6 +73,7 @@ class AstBuilder(val eq: MathParser.EqContext) { when { expo.EXP() !== null -> Operation(Operator.EXP, buildExpo(expo.expo()), if (expo.SUB() !== null) UnaryOperation(Operator.SUB, buildFactor(expo.factor())) else buildFactor(expo.factor())) expo.factor() !== null -> buildFactor(expo.factor()) + expo.unicode_expo() !== null -> Operation(Operator.EXP, buildExpo(expo.expo()), Num(expo.unicode_expo().text.map { superscriptMap[it] }.joinToString(""))) else -> throw IllegalArgumentException("not a legal exponential: ${expo.text}") } @@ -85,6 +86,7 @@ class AstBuilder(val eq: MathParser.EqContext) { } private val germanFormat = NumberFormat.getNumberInstance(Locale.GERMAN) + private val superscriptMap = mapOf('⁰' to '0', '¹' to '1', '²' to '2', '³' to '3', '⁴' to '4', '⁵' to '5', '⁶' to '6', '⁷' to '7', '⁸' to '8', '⁹' to '9') init { germanFormat.maximumFractionDigits = germanFormat.maximumIntegerDigits } diff --git a/modules/fbs-core/math-parser/src/test/kotlin/de/thm/ii/fbs/mathParser/MathParserHelperTest.kt b/modules/fbs-core/math-parser/src/test/kotlin/de/thm/ii/fbs/mathParser/MathParserHelperTest.kt index 61717969e..d637d356a 100644 --- a/modules/fbs-core/math-parser/src/test/kotlin/de/thm/ii/fbs/mathParser/MathParserHelperTest.kt +++ b/modules/fbs-core/math-parser/src/test/kotlin/de/thm/ii/fbs/mathParser/MathParserHelperTest.kt @@ -569,4 +569,44 @@ internal class MathParserHelperTest { assertEquals(expected, MathParserHelper.parse("(2^3)^4")) assertEquals(expected, MathParserHelper.parse("2^3^4")) } + + @Test + fun simpleUnicodeExponentTest() { + val expected = Ast( + Operation( + Operator.EXP, + Num(2), + Num(2) + ) + ) + assertEquals(expected, MathParserHelper.parse("2²")) + } + + @Test + fun multiCharacterUnicodeExponentTest() { + val expected = Ast( + Operation( + Operator.EXP, + Num(2), + Num(16) + ) + ) + assertEquals(expected, MathParserHelper.parse("2¹⁶")) + } + + @Test + fun complexUnicodeExponentTest() { + val expected = Ast( + Operation( + Operator.EXP, + Operation( + Operator.EXP, + Num(2), + Num(3) + ), + Num(4) + ) + ) + assertEquals(expected, MathParserHelper.parse("(2³)⁴")) + } } diff --git a/modules/fbs-core/math-parser/src/test/kotlin/de/thm/ii/fbs/mathParser/SemanticAstComparatorTest.kt b/modules/fbs-core/math-parser/src/test/kotlin/de/thm/ii/fbs/mathParser/SemanticAstComparatorTest.kt index fe6d53e6a..c4ff1c6c3 100644 --- a/modules/fbs-core/math-parser/src/test/kotlin/de/thm/ii/fbs/mathParser/SemanticAstComparatorTest.kt +++ b/modules/fbs-core/math-parser/src/test/kotlin/de/thm/ii/fbs/mathParser/SemanticAstComparatorTest.kt @@ -191,4 +191,34 @@ internal class SemanticAstComparatorTest { assertNotNull(SemanticAstComparator(2, RoundingMode.HALF_UP, ignoreNeutralElements = false, applyInverseElements = false, applyCommutativeLaw = false)) assertNotNull(SemanticAstComparator()) } + + @Test + fun differentExponentRepresentationTest() { + assertTrue( + semanticAstComparator.compare( + MathParserHelper.parse("a^2"), + MathParserHelper.parse("a²") + ) + ) + } + + @Test + fun multiCharacterDifferentExponentRepresentationTest() { + assertTrue( + semanticAstComparator.compare( + MathParserHelper.parse("a^{22}"), + MathParserHelper.parse("a²²") + ) + ) + } + + @Test + fun complexDifferentExponentRepresentationTest() { + assertTrue( + semanticAstComparator.compare( + MathParserHelper.parse("2^3^4"), + MathParserHelper.parse("(2³)⁴") + ) + ) + } }