]> gitweb.hamatoma.de Git - jpinet/commitdiff
Scanner: number with suffix, tests completed
authorhama <hama@siduction.net>
Tue, 26 Jul 2016 22:43:11 +0000 (00:43 +0200)
committerhama <hama@siduction.net>
Tue, 26 Jul 2016 22:43:11 +0000 (00:43 +0200)
src/main/java/de/republib/expr/Scanner.java
src/main/java/de/republib/util/StringUtils.java
src/test/java/de/republib/expr/ScannerTest.java

index 6d3d947bca9af36931b24c6672842ac0478dd2e9..5fb54ec23df89f53007331a125ec9cd8891c8765 100644 (file)
@@ -12,12 +12,56 @@ import de.republib.util.I18N;
  *
  */
 public class Scanner {
+       static boolean defaultAllowNumberSuffix = false;
+
+       /**
+        * @return the defaultAllowNumberSuffix
+        */
+       public static boolean getDefaultAllowNumberSuffix() {
+               return Scanner.defaultAllowNumberSuffix;
+       }
+
+       /**
+        * @param defaultAllowNumberSuffix
+        *            the defaultAllowNumberSuffix to set
+        */
+       public static void setDefaultAllowNumberSuffix(boolean defaultAllowNumberSuffix) {
+               Scanner.defaultAllowNumberSuffix = defaultAllowNumberSuffix;
+       }
+
+       /**
+        * Scans a number at the begin of a string.
+        *
+        * @param text
+        *            text starting (or not) with a number. White spaces will be
+        *            ignored
+        * @param defaultValue
+        *            the return value if the text does not start with a number
+        * @return <i>defaultValue</i>: no number found at the begin of the text<br>
+        *         otherwise: the value of the number
+        */
+       public static long stringToLong(String text, long defaultValue) {
+               final Scanner scanner = new Scanner(text);
+               Token token;
+               long rc = defaultValue;
+               try {
+                       token = scanner.nextNotSpaceToken();
+                       if (token.isType(TokenType.INTEGER)) {
+                               rc = token.getLongValue();
+                       }
+               } catch (final ParserException e) {
+               }
+               return rc;
+       }
+
        int position = 0;
        int lineNo = 1;
        String text;
        Token[] tokens = new Token[3];
        int indexToken = 0;
+       boolean allowNumberSuffix = Scanner.defaultAllowNumberSuffix;
        Token lastToken = null;
+
        StringBuilder string = new StringBuilder(8096);
 
        /**
@@ -152,6 +196,13 @@ public class Scanner {
                return rc;
        }
 
+       /**
+        * @return the allowNumberSuffix
+        */
+       public boolean isAllowNumberSuffix() {
+               return this.allowNumberSuffix;
+       }
+
        /**
         * Returns the next token which is not a SPACE token.
         *
@@ -197,25 +248,7 @@ public class Scanner {
                                }
                                token.setSpace(this.text.substring(tokenStart, this.position));
                        } else if (Character.isDigit(cc)) {
-                               long value = cc - '0';
-                               long digit;
-                               if (this.position < this.text.length() && (cc = this.text.charAt(this.position)) == 'x' || cc == 'X') {
-                                       ++this.position;
-                                       while (this.position < this.text.length()
-                                                       && (Character.isDigit(cc = this.text.charAt(this.position)) || cc >= 'A' && cc <= 'F'
-                                                                       || cc >= 'a' && cc <= 'f')) {
-                                               this.position++;
-                                               digit = cc <= '9' ? cc - '0' : cc <= 'F' ? cc - 'A' + 10 : cc - 'a' + 10;
-                                               value = 16 * value + digit;
-                                       }
-                               } else {
-                                       while (this.position < this.text.length()
-                                                       && Character.isDigit(cc = this.text.charAt(this.position))) {
-                                               this.position++;
-                                               value = 10 * value + cc - '0';
-                                       }
-                               }
-                               token.setLong(value);
+                               token.setLong(scanNumber(cc));
                        } else if (cc == '\'' || cc == '"') {
                                this.string.setLength(0);
                                final char delimiter = cc;
@@ -254,4 +287,81 @@ public class Scanner {
                this.lineNo = 1;
                return this;
        }
+
+       /**
+        * Handles the scan of a number.
+        *
+        * <pre>
+        * Syntax:
+        * <number> ::= <digit><suffix>
+        * <digits ::= '0' 'x' { <hex_digit> }+ | { <decimal_digits> }+
+        * <suffix> ::= <unit> | <unit> 'i'
+        * <decimal_digit> ::= '0' | .. | '9'
+        * <hex_digit> ::= <decimal_digit> | 'a' | .. | 'f'
+        * <unit> ::= 'k' | 'm' | 'g' | 't'
+        * </pre>
+        *
+        * @param cc
+        *            first digit
+        * @return the number
+        */
+       private long scanNumber(char cc) {
+               long value = cc - '0';
+               long digit;
+               if (this.position < this.text.length() && (cc = this.text.charAt(this.position)) == 'x' || cc == 'X') {
+                       ++this.position;
+                       while (this.position < this.text.length() && (Character.isDigit(cc = this.text.charAt(this.position))
+                                       || cc >= 'A' && cc <= 'F' || cc >= 'a' && cc <= 'f')) {
+                               this.position++;
+                               digit = cc <= '9' ? cc - '0' : cc <= 'F' ? cc - 'A' + 10 : cc - 'a' + 10;
+                               value = 16 * value + digit;
+                       }
+               } else {
+                       while (this.position < this.text.length() && Character.isDigit(cc = this.text.charAt(this.position))) {
+                               this.position++;
+                               value = 10 * value + cc - '0';
+                       }
+               }
+               if (this.allowNumberSuffix && (cc == 'k' || cc == 'K' || cc == 'm' || cc == 'M' || cc == 'g' || cc == 'G'
+                               || cc == 't' || cc == 'T') && this.position < this.text.length()) {
+                       ++this.position;
+                       final int len = this.text.length();
+                       char cc2 = '\0';
+                       if (this.position < len) {
+                               cc2 = this.text.charAt(this.position);
+                       }
+                       final boolean binary = cc2 == 'i' || cc2 == 'I';
+                       if (binary) {
+                               ++this.position;
+                       }
+                       switch (cc) {
+                       case 'k':
+                       case 'K':
+                               value *= binary ? 1024L : 1000;
+                               break;
+                       case 'm':
+                       case 'M':
+                               value *= binary ? 1024L * 1024 : 1000L * 1000;
+                               break;
+                       case 'g':
+                       case 'G':
+                               value *= binary ? 1024L * 1024 * 1024 : 1000L * 1000 * 1000;
+                               break;
+                       case 't':
+                       case 'T':
+                               value *= binary ? 1024L * 1024 * 1024 * 1024 : 1000L * 1000 * 1000 * 1000;
+                               break;
+                       }
+               }
+
+               return value;
+       }
+
+       /**
+        * @param allowNumberSuffix
+        *            the allowNumberSuffix to set
+        */
+       public void setAllowNumberSuffix(boolean allowNumberSuffix) {
+               this.allowNumberSuffix = allowNumberSuffix;
+       }
 }
index e9c0c6ed3d7632b46cbd1125ac00415568dc6f4c..e233c00d7046df099eac43960aed3503f01a1a6c 100644 (file)
@@ -27,21 +27,17 @@ public class StringUtils {
                }
                double upperLimit = 1E6;
                double lowerLimit = 100;
-               double lowerLimit2 = 1e-4;
                int prec = 0;
-               final int prec2 = 5;
                switch (precision) {
                case 1:
                        prec = 1;
                        upperLimit = 1E4;
                        lowerLimit = 10.0;
-                       lowerLimit2 = 1e-2;
                        break;
                case 2:
                        prec = 2;
                        upperLimit = 1E5;
                        lowerLimit = 100.0;
-                       lowerLimit2 = 1e-3;
                        break;
                case 3:
                        prec = 3;
@@ -62,33 +58,4 @@ public class StringUtils {
                }
                return rc;
        }
-
-       /**
-        * Evaluate a arithmetic expression.
-        *
-        * @param expr
-        *            a formula with '+', '-', '*', '/', "**" and numbers but no
-        *            parentheses
-        * @return the result
-        */
-       long numberOf(final String expr) throws Exception {
-               long rc = 0;
-               final String[] terms = expr.split("[-+]");
-               if (terms.length == 1) {
-                       rc = Long.parseLong(expr);
-               } else {
-                       for (final String term : terms) {
-                               final String[] factors = term.split("[*/]");
-                               if (factors.length == 1) {
-
-                               } else {
-                                       for (final String factor : factors) {
-                                               final long rc2 = 1;
-                                               final String[] parts = factor.split("\\*\\*");
-                                       }
-                               }
-                       }
-               }
-               return rc;
-       }
 }
index 6ebab9f7ccab14a433200a26a8feba1a34ac6497..b2ab884cf32b2acbe2b1ee6a92644b551920895a 100644 (file)
@@ -3,11 +3,6 @@ package de.republib.expr;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import de.republib.expr.ParserException;
-import de.republib.expr.Scanner;
-import de.republib.expr.Token;
-import de.republib.expr.TokenType;
-
 public class ScannerTest {
        @Test
        public void shouldConstruct() {
@@ -127,6 +122,44 @@ public class ScannerTest {
                Assert.assertEquals(token.getLongValue(), 0xABCDEF0L);
        }
 
+       @Test
+       public void shouldScanNumberSuffix() throws ParserException {
+               // decimal suffixes:
+               final Scanner scanner = new Scanner("12k ix");
+               scanner.setAllowNumberSuffix(true);
+               Assert.assertEquals(scanner.nextToken().getLongValue(), 12 * 1000L);
+               Assert.assertEquals(scanner.reset("123457890K").nextToken().getLongValue(), 123457890L * 1000);
+
+               Assert.assertEquals(scanner.reset("9876m").nextToken().getLongValue(), 9876L * 1000 * 1000);
+               Assert.assertEquals(scanner.reset("04711M").nextToken().getLongValue(), 4711L * 1000 * 1000);
+
+               Assert.assertEquals(scanner.reset("3g").nextToken().getLongValue(), 3L * 1000 * 1000 * 1000);
+               Assert.assertEquals(scanner.reset("9G").nextToken().getLongValue(), 9L * 1000 * 1000 * 1000);
+
+               Assert.assertEquals(scanner.reset("17t").nextToken().getLongValue(), 17L * 1000 * 1000 * 1000 * 1000);
+               Assert.assertEquals(scanner.reset("73T").nextToken().getLongValue(), 73L * 1000 * 1000 * 1000 * 1000);
+
+               // binary suffixes:
+               Assert.assertEquals(scanner.reset("0x23ki").nextToken().getLongValue(), 0x23L * 1024L);
+               Assert.assertEquals(scanner.reset("0x123457890KI").nextToken().getLongValue(), 0x123457890L * 1024);
+
+               Assert.assertEquals(scanner.reset("0x9876mi").nextToken().getLongValue(), 0x9876L * 1024 * 1024);
+               Assert.assertEquals(scanner.reset("0x04711MI").nextToken().getLongValue(), 0x4711L * 1024 * 1024);
+
+               Assert.assertEquals(scanner.reset("0x30gi").nextToken().getLongValue(), 0x30L * 1024 * 1024 * 1024);
+               Assert.assertEquals(scanner.reset("0x90GI").nextToken().getLongValue(), 0x90L * 1024 * 1024 * 1024);
+
+               Assert.assertEquals(scanner.reset("0x17ti").nextToken().getLongValue(), 0x17L * 1024 * 1024 * 1024 * 1024);
+               Assert.assertEquals(scanner.reset("0x73TI").nextToken().getLongValue(), 0x73L * 1024 * 1024 * 1024 * 1024);
+
+               // token behind the suffix:
+               Assert.assertEquals(scanner.reset("123k+").nextToken().getLongValue(), 123L * 1000);
+               Assert.assertTrue(scanner.nextToken().isOp(OpCode.PLUS));
+
+               Assert.assertEquals(scanner.reset("123kI*").nextToken().getLongValue(), 123L * 1024);
+               Assert.assertTrue(scanner.nextToken().isOp(OpCode.TIMES));
+       }
+
        @Test
        public void shouldScanOp() throws ParserException {
                final Scanner scanner = new Scanner("+ - * / % ** ( )");
@@ -271,4 +304,16 @@ public class ScannerTest {
                Assert.assertEquals(token.getDelimiter(), '\'');
        }
 
+       @Test
+       public void shouldWorkStringToLong() {
+               Assert.assertEquals(Scanner.stringToLong(" \t123abc", -1), 123L);
+               final boolean oldValue = Scanner.getDefaultAllowNumberSuffix();
+               // suffix recognition is not switched on
+               Scanner.setDefaultAllowNumberSuffix(false);
+               Assert.assertEquals(Scanner.stringToLong("0x44a2k", -1), 0x44a2L);
+               // suffix recognition is switched on
+               Scanner.setDefaultAllowNumberSuffix(true);
+               Assert.assertEquals(Scanner.stringToLong("0x44a2k", -1), 0x44a2L * 1000);
+               Scanner.setDefaultAllowNumberSuffix(oldValue);
+       }
 }