IntervalEvaluator.java 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package com.sundata.internalevaluation.model.antlr;
  2. import org.antlr.v4.runtime.ANTLRInputStream;
  3. import org.antlr.v4.runtime.CharStream;
  4. import org.antlr.v4.runtime.CharStreams;
  5. import org.antlr.v4.runtime.CommonTokenStream;
  6. import org.antlr.v4.runtime.tree.ParseTree;
  7. import org.antlr.v4.runtime.tree.ParseTreeWalker;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. public class IntervalEvaluator {
  11. private final Map<Interval, Integer> intervals = new HashMap<>();
  12. public static void main(String[] args) {
  13. String input = """
  14. -> [0,10) -> 10
  15. -> (10,20) -> 20
  16. -> [20,30] -> 30
  17. -> (30,+] -> 40
  18. -> [-,+] -> 100
  19. -> [] -> 0
  20. """;
  21. CharStream stream = CharStreams.fromString(input);
  22. // 1. 词法分析
  23. IntervalParserLexer lexer = new IntervalParserLexer(stream);
  24. CommonTokenStream tokens = new CommonTokenStream(lexer);
  25. IntervalParserParser parser = new IntervalParserParser(tokens);
  26. IntervalEvaluator evaluator = new IntervalEvaluator();
  27. evaluator.parseAndEvaluate(parser.parse());
  28. // 测试不同的输入值
  29. System.out.println(evaluator.evaluate(15)); // 输出 20
  30. System.out.println(evaluator.evaluate(25)); // 输出 30
  31. System.out.println(evaluator.evaluate(5)); // 输出 10
  32. System.out.println(evaluator.evaluate(null));// 输出 0
  33. }
  34. public void parseAndEvaluate(ParseTree tree) {
  35. ParseTreeWalker.DEFAULT.walk(new IntervalListener(this), tree);
  36. }
  37. public int evaluate(Number x) {
  38. if (x == null) {
  39. return intervals.get(new Interval(true, null, null));
  40. }
  41. for (Map.Entry<Interval, Integer> entry : intervals.entrySet()) {
  42. Interval interval = entry.getKey();
  43. if (interval.contains(x.doubleValue())) {
  44. return entry.getValue();
  45. }
  46. }
  47. return intervals.get(new Interval(false, null, null));
  48. }
  49. private static class Interval {
  50. private final boolean empty;
  51. private final Double lower;
  52. private final Double upper;
  53. private final boolean lowerInclusive;
  54. private final boolean upperInclusive;
  55. public Interval(boolean empty, Double lower, Double upper) {
  56. this.empty = empty;
  57. this.lower = lower;
  58. this.upper = upper;
  59. this.lowerInclusive = false;
  60. this.upperInclusive = false;
  61. }
  62. public Interval(boolean lowerInclusive, Double lower, boolean upperInclusive, Double upper) {
  63. this.empty = false;
  64. this.lower = lower;
  65. this.upper = upper;
  66. this.lowerInclusive = lowerInclusive;
  67. this.upperInclusive = upperInclusive;
  68. }
  69. public boolean contains(double value) {
  70. if (empty) {
  71. return false;
  72. }
  73. boolean lowerValid = lower == null || (lowerInclusive ? value >= lower : value > lower);
  74. boolean upperValid = upper == null || (upperInclusive ? value <= upper : value < upper);
  75. return lowerValid && upperValid;
  76. }
  77. @Override
  78. public boolean equals(Object o) {
  79. if (this == o) return true;
  80. if (o == null || getClass() != o.getClass()) return false;
  81. Interval interval = (Interval) o;
  82. if (empty != interval.empty) return false;
  83. if (lower != null ? !lower.equals(interval.lower) : interval.lower != null) return false;
  84. if (upper != null ? !upper.equals(interval.upper) : interval.upper != null) return false;
  85. if (lowerInclusive != interval.lowerInclusive) return false;
  86. return upperInclusive == interval.upperInclusive;
  87. }
  88. @Override
  89. public int hashCode() {
  90. int result = (empty ? 1 : 0);
  91. result = 31 * result + (lower != null ? lower.hashCode() : 0);
  92. result = 31 * result + (upper != null ? upper.hashCode() : 0);
  93. result = 31 * result + (lowerInclusive ? 1 : 0);
  94. result = 31 * result + (upperInclusive ? 1 : 0);
  95. return result;
  96. }
  97. }
  98. private static class IntervalListener extends IntervalParserBaseListener {
  99. private final IntervalEvaluator evaluator;
  100. public IntervalListener(IntervalEvaluator evaluator) {
  101. this.evaluator = evaluator;
  102. }
  103. @Override
  104. public void enterLine(IntervalParserParser.LineContext ctx) {
  105. IntervalParserParser.IntervalContext intervalCtx = ctx.interval();
  106. Interval interval = parseInterval(intervalCtx);
  107. int value = Integer.parseInt(ctx.value().NUMBER().getText());
  108. evaluator.intervals.put(interval, value);
  109. }
  110. private Interval parseInterval(IntervalParserParser.IntervalContext ctx) {
  111. if (ctx.getChild(0).getText().equals("[")) {
  112. if (ctx.getChildCount() == 2) {
  113. return new Interval(true, null, null);
  114. }
  115. boolean lowerInclusive = ctx.getChild(0).getText().equals("[");
  116. boolean upperInclusive = ctx.getChild(ctx.getChildCount() - 1).getText().equals("]");
  117. Double lower = ctx.lower != null ? Double.parseDouble(ctx.lower.getText()) : null;
  118. Double upper = ctx.upper != null ? Double.parseDouble(ctx.upper.getText()) : null;
  119. if (ctx.getChild(1).getText().equals("-")) {
  120. return new Interval(false, null, null);
  121. }
  122. return new Interval(lowerInclusive, lower, upperInclusive, upper);
  123. } else {
  124. boolean lowerInclusive = ctx.getChild(0).getText().equals("(");
  125. boolean upperInclusive = ctx.getChild(ctx.getChildCount() - 1).getText().equals("]");
  126. Double lower = ctx.lower != null ? Double.parseDouble(ctx.lower.getText()) : null;
  127. Double upper = ctx.upper != null ? Double.parseDouble(ctx.upper.getText()) : null;
  128. if (upper != null && upper.toString().equals("+")) {
  129. upper = null;
  130. }
  131. return new Interval(lowerInclusive, lower, upperInclusive, upper);
  132. }
  133. }
  134. }
  135. }